openflow build environment setup

This commit is contained in:
2025-11-11 16:45:43 +08:00
parent be0a7ad9b3
commit 50ecb9a23f
2767 changed files with 62766 additions and 649828 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
openbox/
openbox_1/
include.tgz
lib.tgz
case.tgz

BIN
case.tgz

Binary file not shown.

View File

@ -1,8 +1,11 @@
CC=gcc
CC = arm-linux-gnueabihf-gcc
CFLAGS += -I./include -L./lib
LDLIBS = -lofp -lrule -lua -lreg -lpcap -lnet -lpthread
LDLIBS = -lofp -lrule -lua -lreg -lpcap -lnet -lpthread
user_openflow:main_user_openflow.c
$(CC) -o user_openflow main_user_openflow.c $(LDLIBS)
$(CC) $(CFLAGS) -o user_openflow main_user_openflow.c $(LDLIBS)
clean:
rm -rf user_openflow *.o

Binary file not shown.

View File

@ -0,0 +1,94 @@
#ifndef CLICK_ALGORITHM_HH
#define CLICK_ALGORITHM_HH
CLICK_DECLS
template <typename T>
inline T *find(T *begin, T *end, const T &val)
{
while (begin < end && *begin != val)
++begin;
return begin;
}
template <typename T>
inline const T *find(const T *begin, const T *end, const T &val)
{
while (begin < end && *begin != val)
++begin;
return begin;
}
template <typename T>
inline void ignore_result(T result)
{
(void) result;
}
/** @brief Exchange the values of @a a and @a b.
*
* The generic version constructs a temporary copy of @a a. Some
* specializations avoid this copy. */
template <typename T>
inline void click_swap(T &a, T &b)
{
T tmp(a);
a = b;
b = tmp;
}
/** @brief Replace @a x with a default-constructed object.
*
* Unlike @a x.clear(), this function usually frees all memory associated with
* @a x. */
template <typename T>
inline void clear_by_swap(T &x)
{
T tmp;
click_swap(x, tmp);
}
/** @brief Assign @a x to a copy of @a y, possibly modifying @a y.
*
* This is like @a x = @a y, except that under certain circumstances
* it can modify @a y (for example, by calling @a x.swap(@a y)). */
template <typename T, typename V>
inline void assign_consume(T &x, const V &y)
{
x = y;
}
template <typename T, typename U = void> struct do_nothing;
/** @brief Binary function object that does nothing when called. */
template <typename T, typename U>
struct do_nothing {
typedef T first_argument_type;
typedef U second_argument_type;
typedef void result_type;
void operator()(const T &, const U &) {
}
};
/** @brief Unary function object that does nothing when called. */
template <typename T>
struct do_nothing<T, void> {
typedef T argument_type;
typedef void result_type;
void operator()(const T &) {
}
};
/** @brief Function object that encapsulates operator<(). */
template <typename T>
struct less {
typedef T first_argument_type;
typedef T second_argument_type;
typedef bool result_type;
bool operator()(const T &x, const T &y) {
return x < y;
}
};
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,76 @@
// -*- c-basic-offset: 4; related-file-name: "../../lib/archive.cc" -*-
#ifndef CLICK_ARCHIVE_HH
#define CLICK_ARCHIVE_HH
#include <click/string.hh>
#include <click/vector.hh>
CLICK_DECLS
class ErrorHandler;
/** @file <click/archive.hh>
* @brief Class for handling 'ar' archives. */
/** @class ArchiveElement
* @brief Member of an 'ar' archive.
*
* The ArchiveElement class represents members of ar(1) archives. Click uses
* the simple ar(1) format for passing configurations with additional
* information, such as compiled packages and element maps. An archive member
* consists of a name, data, and additional metadata. Complete archives are
* represented as vectors of ArchiveElement objects. */
struct ArchiveElement {
String name; ///< Member name (no slashes allowed)
int date; ///< Decimal seconds since the epoch (1/1/1970)
int uid; ///< User ID of member
int gid; ///< Group ID of member
int mode; ///< File mode
String data; ///< Member contents
/** @brief Return true iff the member should be included in an archive. */
bool live() const {
return name;
}
/** @brief Kill a member, preventing it from being archived. */
void kill() {
name = String();
}
/** @brief Parse a string into a vector of ArchiveElement objects.
* @param str input string
* @param[out] ar archive elements
* @param errh error message receiver
* @return 0 on success, < 0 on failure */
static int parse(const String &str, Vector<ArchiveElement> &ar,
ErrorHandler *errh = 0);
/** @brief Unparse a vector of ArchiveElement objects into a string.
* @param ar archive elements
* @param errh error message receiver
* @return archive string, suitable for parse() */
static String unparse(const Vector<ArchiveElement> &ar,
ErrorHandler *errh = 0);
/** @brief Locate an ArchiveElement in an archive by name.
* @param ar archive elements
* @param name element name
* @return pointer to matching archive element, or 0 if none exists */
static ArchiveElement *find(Vector<ArchiveElement> &ar, const String &name) {
for (ArchiveElement *ae = ar.begin(); ae != ar.end(); ++ae)
if (ae->name == name)
return ae;
return 0;
}
/** @overload */
static const ArchiveElement *find(const Vector<ArchiveElement> &ar, const String &name) {
for (const ArchiveElement *ae = ar.begin(); ae != ar.end(); ++ae)
if (ae->name == name)
return ae;
return 0;
}
};
CLICK_ENDDECLS
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,121 @@
#ifndef CLICK_ARRAY_MEMORY_HH
#define CLICK_ARRAY_MEMORY_HH 1
#include <click/glue.hh>
#include <click/type_traits.hh>
#if HAVE_VALGRIND && HAVE_VALGRIND_MEMCHECK_H
# include <valgrind/memcheck.h>
#endif
CLICK_DECLS
template <size_t s> class sized_array_memory { public:
typedef char_array<s> type;
template <typename T> static type *cast(T *x) {
static_assert(sizeof(type) == s, "char_array<> size off");
return reinterpret_cast<type *>(x);
}
template <typename T> static const type *cast(const T *x) {
return reinterpret_cast<const type *>(x);
}
static void fill(void *a, size_t n, const void *x) {
for (; n != 0; --n, a = (char *) a + s)
memcpy(a, x, s);
}
static void move_construct(void* a, void* x) {
memcpy(a, x, s);
}
static void copy(void *dst, const void *src, size_t n) {
if (n)
memcpy(dst, src, n * s);
}
static void move(void *dst, const void *src, size_t n) {
if (n)
memmove(dst, src, n * s);
}
static void move_onto(void *dst, const void *src, size_t n) {
if (n)
memmove(dst, src, n * s);
}
static void destroy(void *a, size_t n) {
(void) a, (void) n;
}
static void mark_noaccess(void *a, size_t n) {
#ifdef VALGRIND_MAKE_MEM_NOACCESS
VALGRIND_MAKE_MEM_NOACCESS(a, n * s);
#else
(void) a, (void) n;
#endif
}
static void mark_undefined(void *a, size_t n) {
#ifdef VALGRIND_MAKE_MEM_UNDEFINED
VALGRIND_MAKE_MEM_UNDEFINED(a, n * s);
#else
(void) a, (void) n;
#endif
}
};
template <typename T> class typed_array_memory { public:
typedef T type;
static T *cast(T *x) {
return x;
}
static const T *cast(const T *x) {
return x;
}
static void fill(T *a, size_t n, const T *x) {
for (size_t i = 0; i != n; ++i)
new((void *) &a[i]) T(*x);
}
static void move_construct(T* a, T* x) {
#if HAVE_CXX_RVALUE_REFERENCES
new((void *) a) T(click_move(*x));
#else
new((void *) a) T(*x);
#endif
}
static void copy(T *dst, const T *src, size_t n) {
for (size_t i = 0; i != n; ++i)
new((void *) &dst[i]) T(src[i]);
}
static void move(T *dst, const T *src, size_t n) {
if (dst > src && src + n > dst) {
for (dst += n - 1, src += n - 1; n != 0; --n, --dst, --src) {
new((void *) dst) T(*src);
src->~T();
}
} else {
for (size_t i = 0; i != n; ++i) {
new((void *) &dst[i]) T(src[i]);
src[i].~T();
}
}
}
static void move_onto(T *dst, const T *src, size_t n) {
if (dst > src && src + n > dst) {
for (dst += n - 1, src += n - 1; n != 0; --n, --dst, --src) {
dst->~T();
new((void *) dst) T(*src);
}
} else {
for (size_t i = 0; i != n; ++i) {
dst[i].~T();
new((void *) &dst[i]) T(src[i]);
}
}
}
static void destroy(T *a, size_t n) {
for (size_t i = 0; i != n; ++i)
a[i].~T();
}
static void mark_noaccess(T *a, size_t n) {
sized_array_memory<sizeof(T)>::mark_noaccess(a, n);
}
static void mark_undefined(T *a, size_t n) {
sized_array_memory<sizeof(T)>::mark_undefined(a, n);
}
};
template <typename T> class array_memory : public conditional<has_trivial_copy<T>::value, sized_array_memory<sizeof(T)>, typed_array_memory<T> > {};
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,652 @@
// -*- c-basic-offset: 4 -*-
#ifndef CLICK_ATOMIC_HH
#define CLICK_ATOMIC_HH
#if CLICK_LINUXMODULE
# include <click/glue.hh>
#endif
CLICK_DECLS
#if CLICK_LINUXMODULE
# if HAVE_LINUX_ASM_SYSTEM_H
# include <click/cxxprotect.h>
CLICK_CXX_PROTECT
# include <asm/system.h>
CLICK_CXX_UNPROTECT
# include <click/cxxunprotect.h>
# endif
# define CLICK_ATOMIC_VAL _val.counter
#else
# define CLICK_ATOMIC_VAL _val
#endif
#if defined(__i386__) || defined(__arch_um__) || defined(__x86_64__)
# if CLICK_LINUXMODULE || HAVE_MULTITHREAD
# define CLICK_ATOMIC_X86 1
# endif
# if (CLICK_LINUXMODULE && defined(CONFIG_SMP)) || HAVE_MULTITHREAD
# define CLICK_ATOMIC_LOCK "lock ; "
# else
# define CLICK_ATOMIC_LOCK /* nothing */
# endif
#endif
/** @file <click/atomic.hh>
* @brief An atomic 32-bit integer.
*/
/** @class atomic_uint32_t
* @brief A 32-bit integer with support for atomic operations.
*
* The atomic_uint32_t class represents a 32-bit integer, with support for
* atomic operations. The +=, -=, &=, |=, ++, and -- operations are
* implemented using atomic instructions. There are also atomic swap(),
* fetch_and_add(), dec_and_test(), and compare_swap() operations.
*
* Because of some issues with compiler implementations, atomic_uint32_t has
* no explicit constructor; to set an atomic_uint32_t to a value, use
* operator=.
*
* The atomic_uint32_t only provides true atomic semantics when that has been
* implemented. It has been implemented in the Linux kernel, and at userlevel
* (when --enable-multithread has been defined) for x86 machines. In other
* situations, it's not truly atomic (because it doesn't need to be).
*/
class atomic_uint32_t { public:
// No constructors because, unfortunately, GCC generates worse code. Use
// operator= instead.
inline uint32_t value() const;
inline operator uint32_t() const;
inline atomic_uint32_t &operator=(uint32_t x);
inline atomic_uint32_t &operator+=(int32_t delta);
inline atomic_uint32_t &operator-=(int32_t delta);
inline atomic_uint32_t &operator|=(uint32_t mask);
inline atomic_uint32_t &operator&=(uint32_t mask);
inline void operator++();
inline void operator++(int);
inline void operator--();
inline void operator--(int);
inline uint32_t swap(uint32_t desired);
inline uint32_t fetch_and_add(uint32_t delta);
inline bool dec_and_test();
inline uint32_t compare_swap(uint32_t expected, uint32_t desired);
inline bool compare_and_swap(uint32_t expected, uint32_t desired) CLICK_DEPRECATED;
inline static uint32_t swap(volatile uint32_t &x, uint32_t desired);
inline static void inc(volatile uint32_t &x);
inline static bool dec_and_test(volatile uint32_t &x);
inline static uint32_t compare_swap(volatile uint32_t &x, uint32_t expected, uint32_t desired);
inline static bool compare_and_swap(volatile uint32_t &x, uint32_t expected, uint32_t desired) CLICK_DEPRECATED;
private:
#if CLICK_LINUXMODULE
atomic_t _val;
#elif HAVE_MULTITHREAD
volatile uint32_t _val;
#else
uint32_t _val;
#endif
};
/** @brief Return the value. */
inline uint32_t
atomic_uint32_t::value() const
{
#if CLICK_LINUXMODULE
return atomic_read(&_val);
#else
return CLICK_ATOMIC_VAL;
#endif
}
/** @brief Return the value. */
inline
atomic_uint32_t::operator uint32_t() const
{
return value();
}
/** @brief Set the value to @a x. */
inline atomic_uint32_t &
atomic_uint32_t::operator=(uint32_t x)
{
#if CLICK_LINUXMODULE
atomic_set(&_val, x);
#else
CLICK_ATOMIC_VAL = x;
#endif
return *this;
}
/** @brief Atomically add @a delta to the value. */
inline atomic_uint32_t &
atomic_uint32_t::operator+=(int32_t delta)
{
#if CLICK_LINUXMODULE
atomic_add(delta, &_val);
#elif CLICK_ATOMIC_X86
asm volatile (CLICK_ATOMIC_LOCK "addl %1,%0"
: "=m" (CLICK_ATOMIC_VAL)
: "r" (delta), "m" (CLICK_ATOMIC_VAL)
: "cc");
#else
CLICK_ATOMIC_VAL += delta;
#endif
return *this;
}
/** @brief Atomically subtract @a delta from the value. */
inline atomic_uint32_t &
atomic_uint32_t::operator-=(int32_t delta)
{
#if CLICK_LINUXMODULE
atomic_sub(delta, &_val);
#elif CLICK_ATOMIC_X86
asm volatile (CLICK_ATOMIC_LOCK "subl %1,%0"
: "=m" (CLICK_ATOMIC_VAL)
: "r" (delta), "m" (CLICK_ATOMIC_VAL)
: "cc");
#else
CLICK_ATOMIC_VAL -= delta;
#endif
return *this;
}
/** @brief Atomically bitwise-or the value with @a mask. */
inline atomic_uint32_t &
atomic_uint32_t::operator|=(uint32_t mask)
{
#if CLICK_LINUXMODULE && HAVE_LINUX_ATOMIC_SET_MASK
atomic_set_mask(mask, &_val);
#elif CLICK_ATOMIC_X86
asm volatile (CLICK_ATOMIC_LOCK "orl %1,%0"
: "=m" (CLICK_ATOMIC_VAL)
: "r" (mask), "m" (CLICK_ATOMIC_VAL)
: "cc");
#elif CLICK_LINUXMODULE
# warning "using nonatomic approximation for atomic_uint32_t::operator|="
unsigned long flags;
local_irq_save(flags);
CLICK_ATOMIC_VAL |= mask;
local_irq_restore(flags);
#else
CLICK_ATOMIC_VAL |= mask;
#endif
return *this;
}
/** @brief Atomically bitwise-and the value with @a mask. */
inline atomic_uint32_t &
atomic_uint32_t::operator&=(uint32_t mask)
{
#if CLICK_LINUXMODULE && HAVE_LINUX_ATOMIC_SET_MASK
atomic_clear_mask(~mask, &_val);
#elif CLICK_ATOMIC_X86
asm volatile (CLICK_ATOMIC_LOCK "andl %1,%0"
: "=m" (CLICK_ATOMIC_VAL)
: "r" (mask), "m" (CLICK_ATOMIC_VAL)
: "cc");
#elif CLICK_LINUXMODULE
# warning "using nonatomic approximation for atomic_uint32_t::operator&="
unsigned long flags;
local_irq_save(flags);
CLICK_ATOMIC_VAL &= mask;
local_irq_restore(flags);
#else
CLICK_ATOMIC_VAL &= mask;
#endif
return *this;
}
/** @brief Atomically increment value @a x. */
inline void
atomic_uint32_t::inc(volatile uint32_t &x)
{
#if CLICK_LINUXMODULE
static_assert(sizeof(atomic_t) == sizeof(x), "atomic_t expected to take 32 bits.");
atomic_inc((atomic_t *) &x);
#elif CLICK_ATOMIC_X86
asm volatile (CLICK_ATOMIC_LOCK "incl %0"
: "=m" (x)
: "m" (x)
: "cc");
#else
x++;
#endif
}
/** @brief Atomically increment the value. */
inline void
atomic_uint32_t::operator++()
{
#if CLICK_LINUXMODULE
atomic_inc(&_val);
#elif CLICK_ATOMIC_X86
asm volatile (CLICK_ATOMIC_LOCK "incl %0"
: "=m" (CLICK_ATOMIC_VAL)
: "m" (CLICK_ATOMIC_VAL)
: "cc");
#else
CLICK_ATOMIC_VAL++;
#endif
}
/** @brief Atomically increment the value. */
inline void
atomic_uint32_t::operator++(int)
{
#if CLICK_LINUXMODULE
atomic_inc(&_val);
#elif CLICK_ATOMIC_X86
asm volatile (CLICK_ATOMIC_LOCK "incl %0"
: "=m" (CLICK_ATOMIC_VAL)
: "m" (CLICK_ATOMIC_VAL)
: "cc");
#else
CLICK_ATOMIC_VAL++;
#endif
}
/** @brief Atomically decrement the value. */
inline void
atomic_uint32_t::operator--()
{
#if CLICK_LINUXMODULE
atomic_dec(&_val);
#elif CLICK_ATOMIC_X86
asm volatile (CLICK_ATOMIC_LOCK "decl %0"
: "=m" (CLICK_ATOMIC_VAL)
: "m" (CLICK_ATOMIC_VAL)
: "cc");
#else
CLICK_ATOMIC_VAL--;
#endif
}
/** @brief Atomically decrement the value. */
inline void
atomic_uint32_t::operator--(int)
{
#if CLICK_LINUXMODULE
atomic_dec(&_val);
#elif CLICK_ATOMIC_X86
asm volatile (CLICK_ATOMIC_LOCK "decl %0"
: "=m" (CLICK_ATOMIC_VAL)
: "m" (CLICK_ATOMIC_VAL)
: "cc");
#else
CLICK_ATOMIC_VAL--;
#endif
}
/** @brief Atomically assign the value to @a desired, returning the old value.
*
* Behaves like this, but in one atomic step:
* @code
* uint32_t actual = x;
* x = desired;
* return actual;
* @endcode
*
* Also acts as a memory barrier. */
inline uint32_t
atomic_uint32_t::swap(volatile uint32_t &x, uint32_t desired)
{
#if CLICK_ATOMIC_X86
asm volatile ("xchgl %0,%1"
: "=r" (desired), "=m" (x)
: "0" (desired), "m" (x)
: "memory");
return desired;
#elif CLICK_LINUXMODULE && defined(xchg)
return xchg(&x, desired);
#elif CLICK_LINUXMODULE
# error "need xchg for atomic_uint32_t::swap"
#else
uint32_t actual = x;
x = desired;
return actual;
#endif
}
/** @brief Atomically assign the value to @a desired, returning the old value.
*
* Behaves like this, but in one atomic step:
* @code
* uint32_t old_value = value();
* *this = desired;
* return old_value;
* @endcode
*
* Also acts as a memory barrier. */
inline uint32_t
atomic_uint32_t::swap(uint32_t desired)
{
#if CLICK_LINUXMODULE && defined(xchg)
return atomic_xchg(&_val, desired);
#elif CLICK_LINUXMODULE
# error "need xchg for atomic_uint32_t::swap"
#else
return swap(CLICK_ATOMIC_VAL, desired);
#endif
}
/** @brief Atomically add @a delta to the value, returning the old value.
*
* Behaves like this, but in one atomic step:
* @code
* uint32_t old_value = value();
* *this += delta;
* return old_value;
* @endcode */
inline uint32_t
atomic_uint32_t::fetch_and_add(uint32_t delta)
{
#if CLICK_ATOMIC_X86
asm volatile (CLICK_ATOMIC_LOCK "xaddl %0,%1"
: "=r" (delta), "=m" (CLICK_ATOMIC_VAL)
: "0" (delta), "m" (CLICK_ATOMIC_VAL)
: "cc");
return delta;
#elif CLICK_LINUXMODULE && HAVE_LINUX_ATOMIC_ADD_RETURN
return atomic_add_return(&_val, delta) - delta;
#elif CLICK_LINUXMODULE
# warning "using nonatomic approximation for atomic_uint32_t::fetch_and_add"
unsigned long flags;
local_irq_save(flags);
uint32_t old_value = value();
CLICK_ATOMIC_VAL += delta;
local_irq_restore(flags);
return old_value;
#else
uint32_t old_value = value();
CLICK_ATOMIC_VAL += delta;
return old_value;
#endif
}
/** @brief Atomically decrement @a x, returning true if the new @a x
* is 0.
*
* Behaves like this, but in one atomic step:
* @code
* --x;
* return x == 0;
* @endcode */
inline bool
atomic_uint32_t::dec_and_test(volatile uint32_t &x)
{
#if CLICK_LINUXMODULE
static_assert(sizeof(atomic_t) == sizeof(x), "atomic_t expected to take 32 bits.");
return atomic_dec_and_test((atomic_t *) &x);
#elif CLICK_ATOMIC_X86
uint8_t result;
asm volatile (CLICK_ATOMIC_LOCK "decl %0 ; sete %1"
: "=m" (x), "=qm" (result)
: "m" (x)
: "cc");
return result;
#else
return (--x == 0);
#endif
}
/** @brief Perform a compare-and-swap operation.
* @param x value
* @param expected test value
* @param desired new value
* @return The actual old value. If it equaled @a expected, @a x has been
* set to @a desired.
*
* Behaves like this, but in one atomic step:
* @code
* uint32_t actual = x;
* if (x == expected)
* x = desired;
* return actual;
* @endcode
*
* Also acts as a memory barrier. */
inline uint32_t
atomic_uint32_t::compare_swap(volatile uint32_t &x, uint32_t expected, uint32_t desired)
{
#if CLICK_ATOMIC_X86
asm volatile (CLICK_ATOMIC_LOCK "cmpxchgl %2,%1"
: "=a" (expected), "=m" (x)
: "r" (desired), "0" (expected), "m" (x)
: "cc", "memory");
return expected;
#elif CLICK_LINUXMODULE && defined(cmpxchg)
return cmpxchg(&x, expected, desired);
#elif CLICK_LINUXMODULE
# warning "using nonatomic approximation for atomic_uint32_t::compare_and_swap"
unsigned long flags;
local_irq_save(flags);
uint32_t actual = x;
if (actual == expected)
x = desired;
local_irq_restore(flags);
return actual;
#else
uint32_t actual = x;
if (actual == expected)
x = desired;
return actual;
#endif
}
/** @brief Perform a compare-and-swap operation.
* @param x value
* @param expected test value
* @param desired new value
* @return True if the old @a x equaled @a expected (in which case @a x
* was set to @a desired), false otherwise.
* @deprecated Use compare_swap instead.
*
* Behaves like this, but in one atomic step:
* @code
* uint32_t old_value = x;
* if (x == expected)
* x = desired;
* return old_value == expected;
* @endcode
*
* Also acts as a memory barrier. */
inline bool
atomic_uint32_t::compare_and_swap(volatile uint32_t &x, uint32_t expected, uint32_t desired)
{
#if CLICK_ATOMIC_X86
asm volatile (CLICK_ATOMIC_LOCK "cmpxchgl %2,%0 ; sete %%al"
: "=m" (x), "=a" (expected)
: "r" (desired), "m" (x), "a" (expected)
: "cc", "memory");
return (uint8_t) expected;
#elif CLICK_LINUXMODULE && defined(cmpxchg)
return cmpxchg(&x, expected, desired) == expected;
#elif CLICK_LINUXMODULE
# warning "using nonatomic approximation for atomic_uint32_t::compare_and_swap"
unsigned long flags;
local_irq_save(flags);
uint32_t old_value = x;
if (old_value == expected)
x = desired;
local_irq_restore(flags);
return old_value == expected;
#else
uint32_t old_value = x;
if (old_value == expected)
x = desired;
return old_value == expected;
#endif
}
/** @brief Atomically decrement the value, returning true if the new value
* is 0.
*
* Behaves like this, but in one atomic step:
* @code
* --*this;
* return value() == 0;
* @endcode */
inline bool
atomic_uint32_t::dec_and_test()
{
#if CLICK_LINUXMODULE
return atomic_dec_and_test(&_val);
#elif CLICK_ATOMIC_X86
uint8_t result;
asm volatile (CLICK_ATOMIC_LOCK "decl %0 ; sete %1"
: "=m" (CLICK_ATOMIC_VAL), "=qm" (result)
: "m" (CLICK_ATOMIC_VAL)
: "cc");
return result;
#else
return (--CLICK_ATOMIC_VAL == 0);
#endif
}
/** @brief Perform a compare-and-swap operation.
* @param expected test value
* @param desired new value
* @return The actual old value. If @a expected is returned, the
* value has been set to @a desired.
*
* Behaves like this, but in one atomic step:
* @code
* uint32_t actual = value();
* if (actual == expected)
* *this = desired;
* return actual;
* @endcode
*
* Also acts as a memory barrier. */
inline uint32_t
atomic_uint32_t::compare_swap(uint32_t expected, uint32_t desired)
{
#if CLICK_ATOMIC_X86
asm volatile (CLICK_ATOMIC_LOCK "cmpxchgl %2,%1"
: "=a" (expected), "=m" (CLICK_ATOMIC_VAL)
: "r" (desired), "0" (expected), "m" (CLICK_ATOMIC_VAL)
: "cc", "memory");
return expected;
#elif CLICK_LINUXMODULE && HAVE_LINUX_ATOMIC_CMPXCHG
return atomic_cmpxchg(&_val, expected, desired);
#elif CLICK_LINUXMODULE
# warning "using nonatomic approximation for atomic_uint32_t::compare_swap"
unsigned long flags;
local_irq_save(flags);
uint32_t actual = value();
if (actual == expected)
CLICK_ATOMIC_VAL = desired;
local_irq_restore(flags);
return actual;
#else
uint32_t actual = value();
if (actual == expected)
CLICK_ATOMIC_VAL = desired;
return actual;
#endif
}
/** @brief Perform a compare-and-swap operation.
* @param expected test value
* @param desired new value
* @return True if the old value equaled @a expected (in which case the
* value was set to @a desired), false otherwise.
* @deprecated Use compare_swap instead.
*
* Behaves like this, but in one atomic step:
* @code
* uint32_t old_value = value();
* if (old_value == expected)
* *this = desired;
* return old_value == expected;
* @endcode
*
* Also acts as a memory barrier. */
inline bool
atomic_uint32_t::compare_and_swap(uint32_t expected, uint32_t desired)
{
#if CLICK_ATOMIC_X86
asm volatile (CLICK_ATOMIC_LOCK "cmpxchgl %2,%0 ; sete %%al"
: "=m" (CLICK_ATOMIC_VAL), "=a" (expected)
: "r" (desired), "m" (CLICK_ATOMIC_VAL), "a" (expected)
: "cc", "memory");
return (uint8_t) expected;
#elif CLICK_LINUXMODULE && HAVE_LINUX_ATOMIC_CMPXCHG
return atomic_cmpxchg(&_val, expected, desired) == expected;
#elif CLICK_LINUXMODULE
# warning "using nonatomic approximation for atomic_uint32_t::compare_and_swap"
unsigned long flags;
local_irq_save(flags);
uint32_t old_value = value();
if (old_value == expected)
CLICK_ATOMIC_VAL = desired;
local_irq_restore(flags);
return old_value == expected;
#else
uint32_t old_value = value();
if (old_value == expected)
CLICK_ATOMIC_VAL = desired;
return old_value == expected;
#endif
}
inline uint32_t
operator+(const atomic_uint32_t &a, const atomic_uint32_t &b)
{
return a.value() + b.value();
}
inline uint32_t
operator-(const atomic_uint32_t &a, const atomic_uint32_t &b)
{
return a.value() - b.value();
}
inline bool
operator==(const atomic_uint32_t &a, const atomic_uint32_t &b)
{
return a.value() == b.value();
}
inline bool
operator!=(const atomic_uint32_t &a, const atomic_uint32_t &b)
{
return a.value() != b.value();
}
inline bool
operator>(const atomic_uint32_t &a, const atomic_uint32_t &b)
{
return a.value() > b.value();
}
inline bool
operator<(const atomic_uint32_t &a, const atomic_uint32_t &b)
{
return a.value() < b.value();
}
inline bool
operator>=(const atomic_uint32_t &a, const atomic_uint32_t &b)
{
return a.value() >= b.value();
}
inline bool
operator<=(const atomic_uint32_t &a, const atomic_uint32_t &b)
{
return a.value() <= b.value();
}
typedef atomic_uint32_t uatomic32_t;
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,19 @@
/*
* bighashmap.{cc,hh} -- a hash table template that supports removal
* Eddie Kohler
*
* Copyright (c) 2000 Mazu Networks, Inc.
* Copyright (c) 2003 International Computer Science Institute
*
* 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/hashmap.cc>

View File

@ -0,0 +1,7 @@
#ifndef CLICK_BIGHASHMAP_HH
#define CLICK_BIGHASHMAP_HH
// This file is here for compatibility only.
#include <click/hashmap.hh>
#endif

View File

@ -0,0 +1,101 @@
// -*- c-basic-offset: 4; related-file-name: "../../lib/bighashmap_arena.cc" -*-
#ifndef CLICK_BIGHASHMAP_ARENA_HH
#define CLICK_BIGHASHMAP_ARENA_HH
CLICK_DECLS
class HashMap_Arena { public:
HashMap_Arena(uint32_t element_size);
void use() { _refcount++; }
void unuse();
bool detached() const { return _detached; }
void detach() { _detached = true; }
void *alloc();
void free(void *);
private:
struct Link {
Link *next;
};
Link *_free;
enum { NELEMENTS = 127 }; // not a power of 2 so we don't fall into a
// too-large bucket
char *_cur_buffer;
int _buffer_pos;
uint32_t _element_size;
char **_buffers;
int _nbuffers;
int _buffers_cap;
uint32_t _refcount;
bool _detached;
HashMap_Arena(const HashMap_Arena &);
~HashMap_Arena();
HashMap_Arena &operator=(const HashMap_Arena &);
void *hard_alloc();
friend struct Link; // shut up, compiler
};
class HashMap_ArenaFactory { public:
HashMap_ArenaFactory();
virtual ~HashMap_ArenaFactory();
static void static_initialize();
static void static_cleanup();
static HashMap_Arena *get_arena(uint32_t, HashMap_ArenaFactory * =0);
virtual HashMap_Arena *get_arena_func(uint32_t);
private:
HashMap_Arena **_arenas[2];
int _narenas[2];
static HashMap_ArenaFactory *the_factory;
};
inline void
HashMap_Arena::unuse()
{
_refcount--;
if (_refcount <= 0)
delete this;
}
inline void *
HashMap_Arena::alloc()
{
if (_free) {
void *ret = _free;
_free = _free->next;
return ret;
} else if (_buffer_pos > 0) {
_buffer_pos -= _element_size;
return _cur_buffer + _buffer_pos;
} else
return hard_alloc();
}
inline void
HashMap_Arena::free(void *v)
{
Link *link = reinterpret_cast<Link *>(v);
link->next = _free;
_free = link;
}
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,391 @@
#ifndef CLICK_BIGINT_HH
#define CLICK_BIGINT_HH 1
/*
* bigint.hh -- multiple-precision arithmetic
* Eddie Kohler and the authors of GMP
*
* Copyright (c) 2008 Meraki, Inc.
* Derived from the GNU Multiple Precision Arithmetic Library, which is
* Copyright (c) 2001-2008 Free Software Foundation, Inc.
*
* This source code is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* Using the interfaces provided by this file does not create a derived work.
*/
#include <click/integers.hh>
#include <click/type_traits.hh>
#include <click/string.hh>
CLICK_DECLS
/** @file <click/bigint.hh>
* @brief Simple multiple-precision integer arithmetic.
*/
/** @class Bigint
* @brief Template for multiple-precision integer arithmetic.
*
* The Bigint template provides a couple simple, but useful, functions for
* multiple-precision integer arithmetic. It is a port of a very limited
* subset of the GNU Multiple Precision Arithmetic library's mpn functionality
* (architecture-generic functions that work on unsigned integers of known
* size).
*
* A multiple-precision integer is an array of "limbs," or machine integers.
* The multiply_add() and divide() functions take arrays of limbs as
* arguments. In such arrays, the least significant limb is stored at array
* index 0.
*
* For example, here's Bigint speak for "x = 0x123_4567_89AB_CDEF * 0x45":
* @code
* // Initialize result
* uint32_t x[2] = { 0, 0 };
* // Define multiplicand; note that least significant comes first
* uint32_t a[2] = { 0x89ABCDEF, 0x1234567 };
* Bigint<uint32_t>::multiply_add(x, a, 2, 0x45);
* @endcode
*
* Bigint is not optimized for speed.
*
* Bigint's template parameter is the type of a limb. Most users will use
* bigint, which is equivalent to Bigint<uint32_t>.
*/
template <typename L, typename Lhalf = L>
class Bigint { public:
/** @brief Type of a limb, the unit of single arithmetic. */
typedef L limb_type;
/** @brief Type of an arithmetic unit no smaller than one-half limb_type. */
typedef Lhalf half_limb_type;
enum {
limb_bits = sizeof(limb_type) * 8,
half_limb_bits = sizeof(limb_type) * 4
};
enum {
limb_high_bit = limb_type(1) << (limb_bits - 1),
limb_half = limb_type(1) << half_limb_bits,
limb_low_mask = limb_half - 1,
limb_zero = limb_type(0)
};
/** @brief Return the less significant half of @a x.
* @invariant low(@a x) + ((limb_type) high(@a x) << half_limb_bits) ==
* @a x */
static inline half_limb_type low(limb_type x) {
return x & limb_low_mask;
}
/** @brief Return the more significant half of @a x. */
static inline half_limb_type high(limb_type x) {
return x >> half_limb_bits;
}
/** @brief Add two-limb integers [@a a1,@a a0] and [@a b1,@a b0], storing
* the result in [@a x1,@a x0].
* @param[out] x1 most significant limb of result
* @param[out] x0 least significant limb of result
* @param a1 most significant limb of addend
* @param a0 least significant limb of addend
* @param b1 most significant limb of addend
* @param b0 least significant limb of addend
*
* Handles carry in the low order limbs. */
static void add(limb_type &x1, limb_type &x0,
limb_type a1, limb_type a0, limb_type b1, limb_type b0) {
x0 = a0 + b0;
x1 = a1 + b1 + (x0 < a0);
}
/** @brief Multiply one-limb integers @a a and @a b, storing the result in
* [@a x1,@a x0].
* @param[out] x1 most significant limb of result
* @param[out] x0 least significant limb of result
* @param a multiplicand
* @param b multiplicand */
static void multiply(limb_type &x1, limb_type &x0,
limb_type a, limb_type b) {
int_multiply(a, b, x0, x1);
}
/** @brief Multiply one-limb integer @a a by half-limb integer @a b,
* storing the result in [@a x1,@a x0].
* @param[out] x1 most significant limb of result
* @param[out] x0 least significant limb of result
* @param a multiplicand
* @param b multiplicand */
static void multiply_half(limb_type &x1, limb_type &x0,
limb_type a, half_limb_type b) {
if (has_fast_int_multiply<limb_type>::value)
multiply(x1, x0, a, b);
else {
half_limb_type al = low(a), ah = high(a);
limb_type r0 = (limb_type) al * b;
limb_type r1 = (limb_type) ah * b;
limb_type r2 = high(r0) + r1;
x1 = (r2 < r1 ? limb_half : limb_zero) + high(r2);
x0 = (r2 << half_limb_bits) + low(r0);
}
}
/** @brief Return the inverse of limb @a x.
*
* Returns the limb @a y that is the largest limb not larger than
* (2**(2*limb_bits))/@a x - (2**limb_bits). If this would yield
* overflow, @a y is the largest possible number (i.e., only ones). */
static limb_type inverse(limb_type x) {
limb_type y1 = ~x, y0 = ~limb_zero;
// now calculate [y1y0] / x
limb_type x1 = high(x), x0 = low(x);
limb_type q1 = y1 / x1;
limb_type r1 = y1 - q1 * x1;
limb_type m = q1 * x0;
r1 = r1 * limb_half | high(y0);
if (r1 < m) {
--q1, r1 += x;
if (r1 >= x && r1 < m)
--q1, r1 += x;
}
r1 -= m;
limb_type q0 = r1 / x1;
limb_type r0 = r1 - q0 * x1;
m = q0 * x0;
r0 = r0 * limb_half | low(y0);
if (r0 < m) {
--q0, r0 += x;
if (r0 >= x && r0 < m)
--q0, r0 += x;
}
return q1 * limb_half | q0;
}
/** @brief Set @a n-limb integer @a a to the value @a b.
* @param[out] a points to @a n-limb result
* @param n number of limbs in @a a
* @param b input value
* @return carry */
static click_uintmax_t set(limb_type *a, int n, click_uintmax_t b) {
while (n > 0) {
*a++ = b;
n--;
b >>= limb_bits;
}
return b;
}
/** @brief Multiply @a n-limb integer @a a by 1-limb integer @a b and add
* the result to @a n-limb integer @a x.
* @param[in,out] x points to @a n-limb addend and result
* @param a points to @a n-limb multiplicand
* @param n number of limbs in @a x and @a a
* @param b 1-limb multiplicand
* @return overflow
*
* Like @a x += @a a * @a b. Both @a x and @a a must have @a n limbs. It
* is safe for @a x and @a a to point to exactly the same memory, but they
* must not otherwise overlap. */
static limb_type multiply_add(limb_type *x, const limb_type *a, int n,
limb_type b) {
limb_type carry = 0;
do {
limb_type x0, x1;
multiply(x1, x0, *a++, b);
x0 += carry;
carry = (x0 < carry) + x1;
x0 += *x;
carry += (x0 < *x);
*x++ = x0;
} while (--n != 0);
return carry;
}
/** @brief Multiply @a n-limb integer @a a by 1-limb integer @a b, add
* 1-limb integer @a carry, and store the result in @a n-limb integer @a x.
* @param[in,out] x points to @a n-limb result
* @param a points to @a n-limb multiplicand
* @param n number of limbs in @a x and @a a
* @param b 1-limb multiplicand
* @param carry 1-limb initial carry
* @return overflow
*
* Like @a x = (@a a * @a b) + @a carry. Both @a x and @a a must have @a
* n limbs. It is safe for @a x and @a a to point to exactly the same
* memory, but they must not otherwise overlap. */
static limb_type multiply(limb_type *x, const limb_type *a, int n,
limb_type b, limb_type carry = 0) {
do {
limb_type x0, x1;
multiply(x1, x0, *a++, b);
x0 += carry;
carry = (x0 < carry) + x1;
*x++ = x0;
} while (--n != 0);
return carry;
}
/** @brief Multiply @a n-limb integer @a a by 1/2-limb integer @a b, add
* 1-limb integer @a carry, and store the result in @a n-limb integer @a x.
* @param[in,out] x points to @a n-limb result
* @param a points to @a n-limb multiplicand
* @param n number of limbs in @a x and @a a
* @param b 1/2-limb multiplicand
* @param carry 1-limb initial carry
* @return overflow
*
* Like @a x = (@a a * @a b) + @a carry. Both @a x and @a a must have @a
* n limbs. It is safe for @a x and @a a to point to exactly the same
* memory, but they must not otherwise overlap. */
static limb_type multiply_half(limb_type *x, const limb_type *a, int n,
half_limb_type b, limb_type carry = 0) {
do {
limb_type x0, x1;
multiply_half(x1, x0, *a++, b);
x0 += carry;
carry = (x0 < carry) + x1;
*x++ = x0;
} while (--n != 0);
return carry;
}
/** @brief Divide @a n-limb integer @a a by 1-limb integer @a b and store
* the result in @a n-limb integer @a x.
* @param[out] x points to @a n-limb result
* @param a points to @a n-limb dividend
* @param n number of limbs in @a x and @a a
* @param b 1-limb divisor
* @return the remainder
*
* Like @a x = @a a / @a b. Both @a x and @a a must have @a n limbs. It
* is safe for @a x and @a a to point to exactly the same memory, but they
* must not otherwise overlap. */
static limb_type divide(limb_type *x, const limb_type *a, int n,
limb_type b) {
x += n - 1; /* Make x point at most significant quotient limb */
a += n - 1; /* Make a point at most significant dividend limb */
limb_type r = 0;
if (b & limb_high_bit) {
/* High quotient limb is 0 or 1, skip a divide step. */
r = *a;
*x = (r >= b);
r -= (b & -*x);
--x, --a, --n;
/* Multiply-by-inverse, divisor already normalized. */
limb_type b_inverse = inverse(b);
while (n > 0) {
preinverted_divide(*x, r, r, *a, b, b_inverse);
--x, --a, --n;
}
} else {
/* Most significant bit of divisor == 0. */
/* Skip a division if high < divisor (high quotient 0). Testing
here before normalizing will still skip as often as
possible. */
if (*a < b) {
r = *a;
*x = 0;
--x, --a, --n;
}
if (n != 0) {
int norm = ffs_msb(b) - 1; // number of most significant 0 bits
b <<= norm;
r <<= norm;
limb_type b_inverse = inverse(b);
limb_type a1 = *a;
r |= (a1 >> (limb_bits - norm));
--a, --n;
while (n > 0) {
limb_type a0 = *a;
preinverted_divide(*x, r, r, ((a1 << norm) | (a0 >> (limb_bits - norm))), b, b_inverse);
--x, --a, --n;
a1 = a0;
}
preinverted_divide(*x, r, r, a1 << norm, b, b_inverse);
r >>= norm;
}
}
return r;
}
/** @brief Return a string representation of @a n-limb integer @a x and
* set @a x to 0.
* @param[in,out] x @a n-limb input, set to zero on output
* @param n number of limbs in @a x
* @param base base (between 2 and 36)
* @param uppercase if true, use uppercase letters for digits >= 10 */
static String unparse_clear(limb_type *x, int n, int base = 10, bool uppercase = false) {
// need d chars, min d s.t. 10^d >= 2^(sizeof(limb_type) * 8 * n)
// == min d s.t. d >= sizeof(limb_type) * 8 * n / lg 10
int div = (base >= 16 ? 4 : (base >= 8 ? 3 : 1));
String s = String::make_uninitialized((n * limb_bits) / div + 1);
char *q = const_cast<char *>(s.end());
assert(base >= 2 && base <= 36);
while (1) {
while (n > 0 && x[n - 1] == 0)
--n;
if (n == 0)
break;
int r = divide(x, x, n, base);
if (r <= 9)
*--q = '0' + r;
else if (uppercase)
*--q = 'A' + r - 10;
else
*--q = 'a' + r - 10;
}
assert(q >= s.begin());
if (q == s.end())
*--q = '0';
return s.substring(q, s.end());
}
private:
/* Divide the two-limb number in (a1,a0) by b, with b_inverse being the
largest limb not larger than (2**(2*limb_bits))/b - (2**limb_bits). If
this would yield overflow, b_inverse should be the largest possible
number (i.e., only ones). For correct operation, the most significant
bit of b has to be set. Put the quotient in q and the remainder in
r. */
/* Like udiv_qrnnd_preinv, but branch-free. */
static void preinverted_divide(limb_type &q, limb_type &r,
limb_type a1, limb_type a0, limb_type b,
limb_type b_inverse) {
limb_type a0_mask = (a0 & limb_high_bit ? ~limb_zero : limb_zero);
limb_type a0_adjusted = a0 + (b & a0_mask);
limb_type x1, x0;
multiply(x1, x0, b_inverse, a1 - a0_mask);
add(x1, x0, x1, x0, a1, a0_adjusted);
limb_type q1 = ~x1;
multiply(x1, x0, q1, b);
add(x1, x0, x1, x0, a1, a0);
x1 -= b;
r = x0 + (b & x1);
q = x1 - q1;
}
};
/** @brief Typical Bigint usage with uint32_t limb_type. */
typedef Bigint<uint32_t> bigint;
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,379 @@
// -*- c-basic-offset: 4; related-file-name: "../../lib/bitvector.cc" -*-
#ifndef CLICK_BITVECTOR_HH
#define CLICK_BITVECTOR_HH
#include <click/glue.hh>
CLICK_DECLS
/** @file <click/bitvector.hh>
* @brief Click's bitvector class. */
/** @class Bitvector
@brief Vector of bits.
The Bitvector class implements a vector of individually addressable bits.
It supports bitwise operations such as |= and &= as well as the usual
assignment and indexing operations.
Bitvectors are stored as arrays of data words with type word_type, each
containing wbits bits. For some purposes it may be faster or easier to
manipulate data words directly. */
class Bitvector {
public:
class Bit;
typedef bool (Bitvector::*unspecified_bool_type)() const;
typedef uint32_t word_type;
enum { wbits = 32, wshift = 5, wmask = 31 };
inline Bitvector();
explicit inline Bitvector(int n);
explicit inline Bitvector(bool bit);
inline Bitvector(int n, bool bit);
inline Bitvector(const Bitvector &x);
inline ~Bitvector();
inline int size() const;
inline Bit operator[](int i);
inline bool operator[](int i) const;
inline Bit force_bit(int i);
inline int word_size() const;
inline int max_word() const;
inline word_type *words();
inline const word_type *words() const;
bool zero() const;
inline operator unspecified_bool_type() const;
inline bool operator!() const;
Bitvector &assign(int n, bool bit);
Bitvector &operator=(const Bitvector &x);
void clear();
void resize(int n);
friend inline bool operator==(const Bitvector &a, const Bitvector &b);
friend inline bool operator!=(const Bitvector &a, const Bitvector &b);
bool nonzero_intersection(const Bitvector &x) const;
inline Bitvector operator~() const;
friend inline Bitvector operator&(Bitvector a, const Bitvector &b);
friend inline Bitvector operator|(Bitvector a, const Bitvector &b);
friend inline Bitvector operator^(Bitvector a, const Bitvector &b);
friend inline Bitvector operator-(Bitvector a, const Bitvector &b);
void flip();
inline void negate();
Bitvector &operator&=(const Bitvector &x);
Bitvector &operator|=(const Bitvector &x);
Bitvector &operator^=(const Bitvector &x);
inline Bitvector &operator-=(const Bitvector &x);
void offset_or(const Bitvector &x, int offset);
void or_with_difference(const Bitvector &x, Bitvector &difference);
void swap(Bitvector &x);
/** @cond never */
typedef word_type data_word_type CLICK_DEPRECATED;
enum { data_word_bits = wbits };
inline word_type *data_words() CLICK_DEPRECATED;
inline const word_type *data_words() const CLICK_DEPRECATED;
/** @endcond never */
private:
enum { ninline = 2, inlinebits = ninline * wbits };
int _max;
word_type *_data;
word_type _f[ninline];
void finish_copy_constructor(const Bitvector &);
inline void clear_last();
void hard_resize(int, bool);
};
/** @class Bitvector::Bit
@brief A wrapper class that acts like a single bit.
Bits are returned by modifiable Bitvectors' operator[]. They act like bools,
but Bit operations actually index into individual bits in some shared word. */
class Bitvector::Bit { public:
inline Bit(Bitvector::word_type &w, int bit_offset);
inline operator bool() const;
inline Bit &operator=(bool x);
inline Bit &operator=(const Bit &x);
inline void flip();
inline Bit &operator&=(bool x);
inline Bit &operator|=(bool x);
inline Bit &operator^=(bool x);
inline Bit &operator-=(bool x);
private:
Bitvector::word_type &_p;
Bitvector::word_type _mask;
};
/** @brief Construct an empty bitvector. */
inline Bitvector::Bitvector()
: _max(-1), _data(_f) {
_f[0] = 0;
}
/** @brief Construct an all-false bitvector with @a n elements.
@pre @a n >= 0 */
inline Bitvector::Bitvector(int n)
: _data(_f) {
assert(n >= 0);
if (n <= inlinebits) {
_max = n - 1;
memset(_f, 0, sizeof(_f));
} else {
_max = -1;
resize(n);
}
}
/** @brief Construct a @a bit-valued length-1 bitvector. */
inline Bitvector::Bitvector(bool bit)
: _max(0), _data(_f) {
_f[0] = bit;
}
/** @brief Construct a @a bit-valued length-@a n bitvector.
@pre @a n >= 0 */
inline Bitvector::Bitvector(int n, bool b)
: _max(-1), _data(_f) {
assign(n, b);
}
/** @brief Construct a bitvector as a copy of @a x. */
inline Bitvector::Bitvector(const Bitvector &x)
: _max(x._max), _data(_f) {
if (_max < inlinebits)
memcpy(_data, x._data, ninline * sizeof(word_type));
else
finish_copy_constructor(x);
}
/** @brief Destroy a bitvector.
All outstanding Bit objects become invalid. */
inline Bitvector::~Bitvector() {
if (_data != _f)
delete[] _data;
}
/** @brief Return the number of bits in the bitvector. */
inline int Bitvector::size() const {
return _max + 1;
}
/** @brief Test if the bitvector contains at least one true bit.
@sa zero() */
inline Bitvector::operator unspecified_bool_type() const {
return !zero() ? &Bitvector::zero : 0;
}
/** @brief Test if the bitvector contains no true bits.
@sa zero() */
inline bool Bitvector::operator!() const {
return zero();
}
/** @brief Return the bit at position @a i.
@pre 0 <= @a i < size() */
inline Bitvector::Bit Bitvector::operator[](int i) {
assert(i >= 0 && i <= _max);
return Bit(_data[i>>wshift], i & wmask);
}
/** @overload */
inline bool Bitvector::operator[](int i) const {
assert(i >= 0 && i <= _max);
return (_data[i>>wshift] & (word_type(1) << (i & wmask))) != 0;
}
/** @brief Return the bit at position @a i, extending if necessary.
If @a i >= size(), then the bitvector is resize()d to length @a i+1,
which adds false bits to fill out the vector.
@pre 0 <= @a i
@post @a i < size() */
inline Bitvector::Bit Bitvector::force_bit(int i) {
assert(i >= 0);
if (i > _max)
resize(i + 1);
return Bit(_data[i>>wshift], i & wmask);
}
/** @brief Return the number of valid data words. */
inline int Bitvector::word_size() const {
return (_max + wbits) >> wshift;
}
/** @brief Return the index of the maximum valid data word. */
inline int Bitvector::max_word() const {
return (_max < 0 ? -1 : _max >> wshift);
}
/** @brief Return a pointer to this bitvector's data words. */
inline Bitvector::word_type *Bitvector::words() {
return _data;
}
/** @overload */
inline const Bitvector::word_type *Bitvector::words() const {
return _data;
}
/** @cond never */
inline Bitvector::word_type *Bitvector::data_words() {
return _data;
}
inline const Bitvector::word_type *Bitvector::data_words() const {
return _data;
}
/** @endcond never */
/** @brief Test bitvectors for equality. */
inline bool operator==(const Bitvector &a, const Bitvector &b) {
return a.size() == b.size()
&& memcmp(a.words(), b.words(), a.word_size() * sizeof(Bitvector::word_type)) == 0;
}
/** @brief Test bitvectors for inequality. */
inline bool operator!=(const Bitvector &a, const Bitvector &b) {
return !(a == b);
}
/** @brief Modify this bitvector by bitwise subtraction with @a x.
@pre @a x.size() == size()
@return *this
Equivalent to <code>*this &= ~@a x</code>. */
inline Bitvector &Bitvector::operator-=(const Bitvector &x) {
return *this &= ~x;
}
/** @brief Flip all bits in this bitvector.
@sa negate() */
inline void Bitvector::negate() {
flip();
}
/** @brief Return the bitwise negation of this bitvector. */
inline Bitvector Bitvector::operator~() const {
Bitvector m = *this;
m.flip();
return m;
}
/** @brief Return the bitwise and of two bitvectors.
@pre @a a.size() == @a b.size() */
inline Bitvector operator&(Bitvector a, const Bitvector &b) {
return a &= b;
}
/** @brief Return the bitwise or of two bitvectors.
@pre @a a.size() == @a b.size() */
inline Bitvector operator|(Bitvector a, const Bitvector &b) {
return a |= b;
}
/** @brief Return the bitwise exclusive or of two bitvectors.
@pre @a a.size() == @a b.size() */
inline Bitvector operator^(Bitvector a, const Bitvector &b) {
return a ^= b;
}
/** @brief Return the bitwise subtraction of two bitvectors.
@pre @a a.size() == @a b.size()
<code>a - b</code> is equivalent to <code>a & ~b</code>. */
inline Bitvector operator-(Bitvector a, const Bitvector &b) {
return a & ~b;
}
inline void click_swap(Bitvector &a, Bitvector &b) {
a.swap(b);
}
inline void assign_consume(Bitvector &a, Bitvector &b) {
a.swap(b);
}
/** @brief Construct a bit at offset @a bit_offset in data word @a w. */
inline Bitvector::Bit::Bit(Bitvector::word_type &w, int bit_offset)
: _p(w), _mask(Bitvector::word_type(1) << bit_offset) {
}
/** @brief Test if this bit is true. */
inline Bitvector::Bit::operator bool() const {
return (_p & _mask) != 0;
}
/** @brief Set this bit to @a x. */
inline Bitvector::Bit &Bitvector::Bit::operator=(bool x) {
if (x)
_p |= _mask;
else
_p &= ~_mask;
return *this;
}
/** @overload */
inline Bitvector::Bit &Bitvector::Bit::operator=(const Bit &x) {
if (x._p & x._mask)
_p |= _mask;
else
_p &= ~_mask;
return *this;
}
/** @brief Flip this bit. */
inline void Bitvector::Bit::flip() {
_p ^= _mask;
}
/** @brief Modify this bit by bitwise and with @a x. */
inline Bitvector::Bit &Bitvector::Bit::operator&=(bool x) {
if (!x)
_p &= ~_mask;
return *this;
}
/** @brief Modify this bit by bitwise or with @a x. */
inline Bitvector::Bit &Bitvector::Bit::operator|=(bool x) {
if (x)
_p |= _mask;
return *this;
}
/** @brief Modify this bit by bitwise exclusive or with @a x. */
inline Bitvector::Bit &Bitvector::Bit::operator^=(bool x) {
if (x)
_p ^= _mask;
return *this;
}
/** @brief Modify this bit by bitwise subtraction with @a x. */
inline Bitvector::Bit &Bitvector::Bit::operator-=(bool x) {
if (x)
_p &= ~_mask;
return *this;
}
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,334 @@
/* -*- related-file-name: "../../lib/clp.c" -*- */
#ifndef LCDF_CLP_H
#define LCDF_CLP_H
#ifdef __cplusplus
extern "C" {
#endif
/* clp.h - Public interface to CLP.
* This file is part of CLP, the command line parser package.
*
* Copyright (c) 1997-2014 Eddie Kohler, ekohler@gmail.com
*
* CLP is free software. It is distributed under the GNU General Public
* License, Version 2, or, alternatively and at your discretion, under the
* more permissive (BSD-like) Click LICENSE file as described below.
*
* 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, which is available in full at
* http://github.com/kohler/click/blob/master/LICENSE. The 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 binding. */
#include <stdio.h>
#include <stdarg.h>
typedef struct Clp_Option Clp_Option;
typedef struct Clp_Parser Clp_Parser;
typedef struct Clp_ParserState Clp_ParserState;
/** @brief Option description.
*
* CLP users declare arrays of Clp_Option structures to specify what options
* should be parsed.
* @sa Clp_NewParser, Clp_SetOptions */
struct Clp_Option {
const char *long_name; /**< Name of long option, or NULL if the option
has no long name. */
int short_name; /**< Character defining short option, or 0 if
the option has no short name. */
int option_id; /**< User-specified ID defining option,
returned by Clp_Next. */
int val_type; /**< ID of option's value type, or 0 if option
takes no value. */
int flags; /**< Option parsing flags. */
};
/** @name Value types
* These values describe the type of an option's argument and are used in
* the Clp_Option val_type field. For example, if an option took integers, its
* Clp_Option structure would have val_type set to Clp_ValInt. */
/**@{*/
#define Clp_NoVal 0 /**< @brief Option takes no value. */
#define Clp_ValString 1 /**< @brief Option value is an
arbitrary string. */
#define Clp_ValStringNotOption 2 /**< @brief Option value is a
non-option string.
See Clp_DisallowOptions. */
#define Clp_ValBool 3 /**< @brief Option value is a
boolean.
Accepts "true", "false", "yes", "no", "1", and "0", or any
prefixes thereof. The match is case-insensitive. */
#define Clp_ValInt 4 /**< @brief Option value is a
signed int.
Accepts an optional "+" or "-" sign, followed by one or more
digits. The digits may be include a "0x" or "0X" prefix, for
a hexadecimal number, or a "0" prefix, for an octal number;
otherwise it is decimal. */
#define Clp_ValUnsigned 5 /**< @brief Option value is an
unsigned int.
Accepts an optional "+" sign, followed by one or more
digits. The digits may be include a "0x" or "0X" prefix, for
a hexadecimal number, or a "0" prefix, for an octal number;
otherwise it is decimal. */
#define Clp_ValLong 6 /**< @brief Option value is a
signed long. */
#define Clp_ValUnsignedLong 7 /**< @brief Option value is an
unsigned long. */
#define Clp_ValDouble 8 /**< @brief Option value is a
double.
Accepts a real number as defined by strtod(). */
#define Clp_ValFirstUser 10 /**< @brief Value types >=
Clp_ValFirstUser are available
for user types. */
/**@}*/
/** @name Option flags
* These flags are used in the Clp_Option flags field. */
/**@{*/
#define Clp_Mandatory (1<<0) /**< @brief Option flag: value
is mandatory.
It is an error if the option has no value. This is the
default if an option has arg_type != 0 and the Clp_Optional
flag is not provided. */
#define Clp_Optional (1<<1) /**< @brief Option flag: value
is optional. */
#define Clp_Negate (1<<2) /**< @brief Option flag: option
may be negated.
--no-[long_name] will be accepted in argument lists. */
#define Clp_OnlyNegated (1<<3) /**< @brief Option flag: option
<em>must</em> be negated.
--no-[long_name] will be accepted in argument lists, but
--[long_name] will not. This is the default if long_name
begins with "no-". */
#define Clp_PreferredMatch (1<<4) /**< @brief Option flag: prefer this
option when matching.
Prefixes of --[long_name] should map to this option, even if
other options begin with --[long_name]. */
/**@}*/
/** @name Option character types
* These flags are used in to define character types in Clp_SetOptionChar(). */
/**@{*/
/* Clp_NotOption 0 */
#define Clp_Short (1<<0) /**< @brief Option character begins
a set of short options. */
#define Clp_Long (1<<1) /**< @brief Option character begins
a long option. */
#define Clp_ShortNegated (1<<2) /**< @brief Option character begins
a set of negated short options. */
#define Clp_LongNegated (1<<3) /**< @brief Option character begins
a negated long option. */
#define Clp_LongImplicit (1<<4) /**< @brief Option character can begin
a long option, and is part of that
long option. */
/**@}*/
#define Clp_NotOption 0 /**< @brief Clp_Next value: argument
was not an option. */
#define Clp_Done -1 /**< @brief Clp_Next value: there are
no more arguments. */
#define Clp_BadOption -2 /**< @brief Clp_Next value: argument
was an erroneous option. */
#define Clp_Error -3 /**< @brief Clp_Next value: internal
CLP error. */
#define Clp_ValSize 40 /**< @brief Minimum size of the
Clp_Parser val.cs field. */
#define Clp_ValIntSize 10 /**< @brief Minimum size of the
Clp_Parser val.is field. */
/** @brief A value parsing function.
* @param clp the parser
* @param vstr the value to be parsed
* @param complain if nonzero, report error messages via Clp_OptionError
* @param user_data user data passed to Clp_AddType()
* @return 1 if parsing succeeded, 0 otherwise
*/
typedef int (*Clp_ValParseFunc)(Clp_Parser *clp, const char *vstr,
int complain, void *user_data);
/** @brief A function for reporting option errors.
* @param clp the parser
* @param message error message
*/
typedef void (*Clp_ErrorHandler)(Clp_Parser *clp, const char *message);
/** @brief Command line parser.
*
* A Clp_Parser object defines an instance of CLP, including allowed options,
* value types, and current arguments.
* @sa Clp_NewParser, Clp_SetOptions, Clp_SetArguments */
struct Clp_Parser {
const Clp_Option *option; /**< The last option. */
int negated; /**< Whether the last option was negated. */
int have_val; /**< Whether the last option had a value. */
const char *vstr; /**< The string value provided with the last
option. */
union {
int i;
unsigned u;
long l;
unsigned long ul;
double d;
const char *s;
void *pv;
#ifdef HAVE_INT64_TYPES
int64_t i64;
uint64_t u64;
#endif
char cs[Clp_ValSize];
unsigned char ucs[Clp_ValSize];
int is[Clp_ValIntSize];
unsigned us[Clp_ValIntSize];
} val; /**< The parsed value provided with the last
option. */
void *user_data; /**< Uninterpreted by CLP; users can set
arbitrarily. */
struct Clp_Internal *internal;
};
/** @cond never */
#if __GNUC__ >= 4
# define CLP_SENTINEL __attribute__((sentinel))
#else
# define CLP_SENTINEL /* nothing */
#endif
/** @endcond never */
/** @brief Create a new Clp_Parser. */
Clp_Parser *Clp_NewParser(int argc, const char * const *argv,
int nopt, const Clp_Option *opt);
/** @brief Destroy a Clp_Parser object. */
void Clp_DeleteParser(Clp_Parser *clp);
/** @brief Return @a clp's program name. */
const char *Clp_ProgramName(Clp_Parser *clp);
/** @brief Set @a clp's program name. */
const char *Clp_SetProgramName(Clp_Parser *clp, const char *name);
/** @brief Set @a clp's error handler function. */
Clp_ErrorHandler Clp_SetErrorHandler(Clp_Parser *clp, Clp_ErrorHandler errh);
/** @brief Set @a clp's UTF-8 mode. */
int Clp_SetUTF8(Clp_Parser *clp, int utf8);
/** @brief Return @a clp's treatment of character @a c. */
int Clp_OptionChar(Clp_Parser *clp, int c);
/** @brief Set @a clp's treatment of character @a c. */
int Clp_SetOptionChar(Clp_Parser *clp, int c, int type);
/** @brief Set @a clp's option definitions. */
int Clp_SetOptions(Clp_Parser *clp, int nopt, const Clp_Option *opt);
/** @brief Set @a clp's arguments. */
void Clp_SetArguments(Clp_Parser *clp, int argc, const char * const *argv);
/** @brief Set whether @a clp is searching for options. */
int Clp_SetOptionProcessing(Clp_Parser *clp, int on);
#define Clp_DisallowOptions (1<<0) /**< @brief Value type flag: value
can't be an option string.
See Clp_AddType(). */
/** @brief Define a new value type for @a clp. */
int Clp_AddType(Clp_Parser *clp, int val_type, int flags,
Clp_ValParseFunc parser, void *user_data);
#define Clp_AllowNumbers (1<<0) /**< @brief String list flag: allow
explicit numbers.
See Clp_AddStringListType() and Clp_AddStringListTypeVec(). */
#define Clp_StringListLong (1<<1) /**< @brief String list flag: values
have long type. */
/** @brief Define a new string list value type for @a clp. */
int Clp_AddStringListTypeVec(Clp_Parser *clp, int val_type, int flags,
int nstrs, const char * const *strs,
const int *vals);
/** @brief Define a new string list value type for @a clp. */
int Clp_AddStringListType(Clp_Parser *clp, int val_type, int flags, ...)
CLP_SENTINEL;
/** @brief Parse and return the next argument from @a clp. */
int Clp_Next(Clp_Parser *clp);
/** @brief Return the next argument from @a clp without option parsing. */
const char *Clp_Shift(Clp_Parser *clp, int allow_options);
/** @brief Create a new Clp_ParserState. */
Clp_ParserState *Clp_NewParserState(void);
/** @brief Destroy a Clp_ParserState object. */
void Clp_DeleteParserState(Clp_ParserState *state);
/** @brief Save @a clp's current state in @a state. */
void Clp_SaveParser(const Clp_Parser *clp, Clp_ParserState *state);
/** @brief Restore parser state from @a state into @a clp. */
void Clp_RestoreParser(Clp_Parser *clp, const Clp_ParserState *state);
/** @brief Report a parser error. */
int Clp_OptionError(Clp_Parser *clp, const char *format, ...);
/** @brief Format a message. */
int Clp_vsnprintf(Clp_Parser* clp, char* str, size_t size,
const char* format, va_list val);
/** @brief Print a message. */
int Clp_fprintf(Clp_Parser* clp, FILE* f, const char* format, ...);
/** @brief Print a message. */
int Clp_vfprintf(Clp_Parser* clp, FILE* f, const char* format, va_list val);
/** @brief Extract the current option as a string. */
int Clp_CurOptionNameBuf(Clp_Parser *clp, char *buf, int len);
/** @brief Extract the current option as a string. */
const char *Clp_CurOptionName(Clp_Parser *clp);
/** @brief Test if the current option had long name @a name. */
int Clp_IsLong(Clp_Parser *clp, const char *long_name);
/** @brief Test if the current option had short name @a name. */
int Clp_IsShort(Clp_Parser *clp, int short_name);
#undef CLP_SENTINEL
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,87 @@
/* include/click/config-bsdmodule.h. Generated from config-bsdmodule.h.in by configure. */
/* Process this file with configure to produce config-bsdmodule.h. -*- mode: c -*- */
#ifndef CLICK_CONFIG_BSDMODULE_H
#define CLICK_CONFIG_BSDMODULE_H
/* Define stuff under a FreeBSD module. */
#ifndef __FreeBSD__
# error "I must be compiled on a FreeBSD machine"
#endif
/* Define if Click should use an adaptive scheduler to share the CPU(s) more
fairly with the kernel. */
/* #undef HAVE_ADAPTIVE_SCHEDULER */
/* Define if your BSD kernel has polling extensions. */
/* #undef HAVE_BSD_POLLING */
/* Define if your BSD kernel has Click extensions. */
/* #undef HAVE_CLICK_BSD_KERNEL */
/* Define if 'int64_t' is typedefed to 'long' in bsdmodule. */
/* #undef HAVE_INT64_IS_LONG_BSDMODULE */
/* Define if 'int64_t' is typedefed to 'long long' in bsdmodule. */
/* #undef HAVE_INT64_IS_LONG_LONG_BSDMODULE */
/* Define to enable assertion checking. Failed assertions will print a message
and optionally stop the router. */
/* #undef HAVE_KERNEL_ASSERT */
/* Define if NETISR scheduling should be used. */
#define BSD_NETISRSCHED 1
/* The size of a `click_jiffies_t', as computed by sizeof. */
#define SIZEOF_CLICK_JIFFIES_T SIZEOF_INT
/* Include integer and other type definitions. */
#include <sys/types.h>
/* Define assert macro. */
# ifdef __cplusplus
extern "C" {
# endif
void click_assert_failed(const char *file, int line, const char *problem_text);
# ifdef __cplusplus
}
# endif
#ifdef HAVE_KERNEL_ASSERT
# define assert(x) ((x) ? (void)0 : click_assert_failed(__FILE__, __LINE__, #x))
#else
# define assert(x) /* nada */
#endif
/* Define likely and unlikely macros. */
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
/* Define HAVE_INT64_IS_LONG based on HAVE_INT64_IS_LONG_BSDMODULE. */
#ifdef HAVE_INT64_IS_LONG_BSDMODULE
# define HAVE_INT64_IS_LONG HAVE_INT64_IS_LONG_BSDMODULE
#endif
/* Define HAVE_INT64_IS_LONG_LONG based on HAVE_INT64_IS_LONG_LONG_BSDMODULE. */
#if HAVE_LONG_LONG && defined(HAVE_INT64_IS_LONG_LONG_BSDMODULE)
# define HAVE_INT64_IS_LONG_LONG HAVE_INT64_IS_LONG_LONG_BSDMODULE
#endif
#ifdef __cplusplus
/* Declare operator new. */
void *operator new(size_t) throw ();
void *operator new[](size_t) throw ();
/* Provide placement new. */
inline void *operator new(size_t, void *v) throw () { return v; }
#define HAVE_PLACEMENT_NEW 1
/* Define macros that surround Click declarations. */
#define CLICK_DECLS namespace Click {
#define CLICK_ENDDECLS }
#define CLICK_USING_DECLS using namespace Click;
#define CLICK_NAME(name) ::Click::name
#endif /* __cplusplus */
#endif /* CLICK_CONFIG_BSDMODULE_H */

View File

@ -0,0 +1,283 @@
/* include/click/config-linuxmodule.h. Generated from config-linuxmodule.h.in by configure. */
/* Process this file with configure to produce config-linuxmodule.h. -*- mode: c -*- */
#ifndef CLICK_CONFIG_LINUXMODULE_H
#define CLICK_CONFIG_LINUXMODULE_H
/* Define if Click should use an adaptive scheduler to share the CPU(s) more
fairly with the kernel. */
/* #undef HAVE_ADAPTIVE_SCHEDULER */
/* Define if the AUTOCONF_INCLUDED symbol should be checked. */
/* #undef HAVE_CHECK_AUTOCONF_INCLUDED */
/* Define if your Linux kernel has Click extensions. */
/* #undef HAVE_CLICK_KERNEL */
/* Define if your Linux kernel has Click transmit notification extensions. */
/* #undef HAVE_CLICK_KERNEL_TX_NOTIFY */
/* Define if your Linux kernel has Click skb_recycle. */
/* #undef HAVE_CLICK_SKB_RECYCLE */
/* Define if fast checksum functions available. */
#define HAVE_FAST_CHECKSUM 1
/* Define if 'int64_t' is typedefed to 'long' in linuxmodule. */
/* #undef HAVE_INT64_IS_LONG_LINUXMODULE */
/* Define if 'int64_t' is typedefed to 'long long' in linuxmodule. */
/* #undef HAVE_INT64_IS_LONG_LONG_LINUXMODULE */
/* Define to enable assertion checking. Failed assertions will print a message
and optionally stop the router. */
/* #undef HAVE_KERNEL_ASSERT */
/* Define if you have the <asm/alternative.h> header file. */
/* #undef HAVE_LINUX_ASM_ALTERNATIVE_H */
/* Define if you have the <asm/scatterlist.h> header file. */
/* #undef HAVE_LINUX_ASM_SCATTERLIST_H */
/* Define if you have the <asm/system.h> header file. */
/* #undef HAVE_LINUX_ASM_SYSTEM_H */
/* Define if your Linux kernel architecture defines atomic_add_return. */
/* #undef HAVE_LINUX_ATOMIC_ADD_RETURN */
/* Define if your Linux kernel architecture defines atomic_set_mask. */
/* #undef HAVE_LINUX_ATOMIC_SET_MASK */
/* Define if your Linux kernel architecture defines atomic_cmpxchg. */
/* #undef HAVE_LINUX_ATOMIC_CMPXCHG */
/* Define if your Linux kernel has files_lock. */
/* #undef HAVE_LINUX_FILES_LOCK */
/* Define if your Linux kernel has files_lglock. */
/* #undef HAVE_LINUX_FILES_LGLOCK */
/* Define if you have the d_make_root function. */
/* #undef HAVE_LINUX_D_MAKE_ROOT */
/* Define if 'struct dentry' has a 'd_child' member. */
/* #undef HAVE_LINUX_DENTRY_D_CHILD */
/* Define if your Linux kernel has dev_ioctl. */
/* #undef HAVE_LINUX_DEV_IOCTL */
/* Define if your Linux kernel has devinet_ioctl. */
/* #undef HAVE_LINUX_DEVINET_IOCTL */
/* Define if your Linux kernel exports get_monotonic_coarse. */
/* #undef HAVE_LINUX_GET_MONOTONIC_COARSE */
/* Define if your Linux kernel exports getboottime. */
/* #undef HAVE_LINUX_GETBOOTTIME */
/* Define if your Linux kernel has inet_ctl_sock_create. */
/* #undef HAVE_LINUX_INET_CTL_SOCK_CREATE */
/* Define if your Linux kernel has inet_ioctl. */
/* #undef HAVE_LINUX_INET_IOCTL */
/* Define if you have the <linux/ktime.h> header file. */
/* #undef HAVE_LINUX_KTIME_H */
/* Define if your Linux kernel exports ktime_mono_to_any. */
/* #undef HAVE_LINUX_KTIME_MONO_TO_ANY */
/* Define if your Linux kernel has polling extensions. */
/* #undef HAVE_LINUX_POLLING */
/* Define if your Linux kernel has read_net_skbcount. */
/* #undef HAVE_LINUX_READ_NET_SKBCOUNT */
/* Define if your Linux kernel has sb_lock. */
/* #undef HAVE_LINUX_SB_LOCK */
/* Define if your Linux kernel has set_cpus_allowed_ptr. */
/* #undef HAVE_LINUX_SET_CPUS_ALLOWED_PTR */
/* Define if 'struct skb_shared_info' has a 'gso_size' member. */
/* #undef HAVE_LINUX_SKB_SHINFO_GSO_SIZE */
/* Define if 'struct skb_shared_info' has an 'ip6_frag_id' member. */
/* #undef HAVE_LINUX_SKB_SHINFO_IP6_FRAG_ID */
/* Define if 'struct skb_shared_info' has an 'tx_flags.flags' member. */
/* #undef HAVE_LINUX_SKB_SHINFO_TX_FLAGS_UNION */
/* Define if 'struct skb_shared_info' has an 'tx_flags' member defining 'SKBTX_DEV_ZEROCOPY'. */
/* #undef HAVE_LINUX_SKB_SHINFO_TX_FLAGS_SKBTX_DEV_ZEROCOPY */
/* Define if 'struct skb_shared_info' has a 'tso_size' member. */
/* #undef HAVE_LINUX_SKB_SHINFO_TSO_SIZE */
/* Define if 'struct skb_shared_info' has a 'ufo_size' member. */
/* #undef HAVE_LINUX_SKB_SHINFO_UFO_SIZE */
/* Define if 'struct sk_buff' has an 'fclone' member. */
/* #undef HAVE_LINUX_SKBUFF_FCLONE */
/* Define if 'struct sk_buff' has a 'security' member. */
/* #undef HAVE_LINUX_SKBUFF_SECURITY */
/* Define if your Linux kernel exposes strlen. */
/* #undef HAVE_LINUX_STRLEN_EXPOSED */
/* Define if 'struct super_block' has an 's_d_op' member. */
/* #undef HAVE_LINUX_SUPER_BLOCK_S_D_OP */
/* Define if your Linux kernel has tulip_interrupt_hook. */
/* #undef HAVE_LINUX_TULIP_INTERRUPT_HOOK */
/* Define if the Click linuxmodule is compiled for a 2.6 or later kernel. */
/* #undef HAVE_LINUXMODULE_2_6 */
/* Define if the linuxmodule driver might run multiple threads. */
/* #undef HAVE_LINUXMODULE_MULTITHREAD */
/* Define if you have the net_enable_timestamp function. */
/* #undef HAVE_NET_ENABLE_TIMESTAMP */
/* Define if you have the netdev_get_tx_queue function. */
/* #undef HAVE_NETDEV_GET_TX_QUEUE */
/* Define if you have the netdev_uses_dsa_tags function. */
/* #undef HAVE_NETDEV_USES_DSA_TAGS */
/* Define if you have the netdev_uses_trailer_tags function. */
/* #undef HAVE_NETDEV_USES_TRAILER_TAGS */
/* Define if your Linux kernel has netdev_rx_handler_register. */
/* #undef HAVE_LINUX_NETDEV_RX_HANDLER_REGISTER */
/* Define if netif_receive_skb takes 3 arguments. */
/* #undef HAVE_NETIF_RECEIVE_SKB_EXTENDED */
/* Define if you have the netif_tx_lock function. */
/* #undef HAVE_NETIF_TX_LOCK */
/* Define if you have the netif_tx_queue_frozen function. */
/* #undef HAVE_NETIF_TX_QUEUE_FROZEN */
/* Define if you have the skb_dst_drop function. */
/* #undef HAVE_SKB_DST_DROP */
/* Define if you have the skb_linearize function. */
/* #undef HAVE_SKB_LINEARIZE */
/* Define if you have the skb_recycle function. */
/* #undef HAVE_SKB_RECYCLE */
/* Define if you have the skb_recycle_check function. */
/* #undef HAVE_SKB_RECYCLE_CHECK */
/* Define if you have the strnlen function. */
#define HAVE_STRNLEN 1
/* Define to 1 if Linux defines the type 'uintptr_t'. */
/* #undef HAVE_UINTPTR_T_LINUXMODULE */
/* The size of a `click_jiffies_t', as computed by sizeof. */
#define SIZEOF_CLICK_JIFFIES_T SIZEOF_LONG
/* Define HAVE_INT64_IS_LONG based on HAVE_INT64_IS_LONG_LINUXMODULE. */
#ifdef HAVE_INT64_IS_LONG_LINUXMODULE
# define HAVE_INT64_IS_LONG HAVE_INT64_IS_LONG_LINUXMODULE
#endif
/* Define HAVE_INT64_IS_LONG_LONG based on HAVE_INT64_IS_LONG_LONG_LINUXMODULE. */
#if defined(HAVE_LONG_LONG) && HAVE_LONG_LONG && defined(HAVE_INT64_IS_LONG_LONG_LINUXMODULE)
# define HAVE_INT64_IS_LONG_LONG HAVE_INT64_IS_LONG_LONG_LINUXMODULE
#endif
/* Define HAVE_MULTITHREAD based on HAVE_LINUXMODULE_MULTITHREAD. */
#ifdef HAVE_LINUXMODULE_MULTITHREAD
# define HAVE_MULTITHREAD HAVE_LINUXMODULE_MULTITHREAD
#endif
/* Define if fast checksum functions require correct alignment. */
#if !defined(__i386__) && !defined(__x86_64__)
# define FAST_CHECKSUM_ALIGNED 1
#endif
/* Below here only for normal Click compiles. */
#ifndef CLICK_CONFIG_LINUXMODULE_SYMBOLS_ONLY
/* Define stuff under a Linux module. */
#ifndef __linux__
# error "I must be compiled on a Linux machine"
#endif
#define __KERNEL__ 1
#define MODULE 1
/* Include Linux configuration and type definitions. */
#if HAVE_CHECK_AUTOCONF_INCLUDED && !defined(AUTOCONF_INCLUDED)
# include <linux/autoconf.h>
#endif
#include <linux/version.h>
#ifdef __cplusplus
# include <click/cxxprotect.h>
# include <asm/types.h>
# include <linux/types.h>
# include <click/cxxunprotect.h>
#else
# include <asm/types.h>
# include <linux/types.h>
#endif
typedef ptrdiff_t intptr_t;
#if !HAVE_UINTPTR_T_LINUXMODULE
typedef unsigned long uintptr_t;
#endif
/* Define KBUILD symbols. */
#if !defined(KBUILD_STR)
# define KBUILD_STR(s) #s
# define KBUILD_BASENAME KBUILD_STR(click)
# define KBUILD_MODNAME KBUILD_STR(click)
#endif
#ifdef __cplusplus
/* Declare operator new. */
void *operator new(size_t) throw ();
void *operator new[](size_t) throw ();
/* Provide placement new. */
inline void *operator new(size_t, void *v) { return v; }
#define HAVE_PLACEMENT_NEW 1
/* Define macros that surround Click declarations. */
#define CLICK_DECLS /* */
#define CLICK_ENDDECLS /* */
#define CLICK_USING_DECLS /* */
#define CLICK_NAME(name) ::name
/* Fix incompatibilities between some Linux versions and Click/C++. */
#include <click/fixconfig.h>
#endif /* __cplusplus */
/* Define assert macro. */
# ifdef __cplusplus
extern "C" {
# endif
void click_assert_failed(const char *file, int line, const char *problem_text);
# ifdef __cplusplus
}
# endif
#ifdef HAVE_KERNEL_ASSERT
# define assert(x) ((x) ? (void)0 : click_assert_failed(__FILE__, __LINE__, #x))
#else
# define assert(x) /* nada */
#endif
/* Some architectures do not have builtin integer functions in kernel. */
#if defined(__MIPSEL__) || defined(__MIPSEB__)
# define HAVE_NO_INTEGER_BUILTINS 1
#endif
#endif /* CLICK_CONFIG_LINUXMODULE_SYMBOLS_ONLY */
#endif /* CLICK_CONFIG_LINUXMODULE_H */

View File

@ -0,0 +1,215 @@
/* include/click/config-minios.h. Generated from config-minios.h.in by configure. */
/* Process this file with configure to produce config-minios.h. -*- mode: c -*- */
#ifndef CLICK_CONFIG_MINIOS_H
#define CLICK_CONFIG_MINIOS_H
/* Define if you have the <byteswap.h> header file. */
#define HAVE_BYTESWAP_H 1
/* Define if you have the clock_gettime function. */
#define HAVE_CLOCK_GETTIME 1
/* Define to 1 if you have the declaration
of 'clock_gettime', and to 0 if you don't. */
#define HAVE_DECL_CLOCK_GETTIME 1
/* Define if you have the ffs function. */
#define HAVE_FFS 1
/* Define if you have the ffsl function. */
#define HAVE_FFSL 1
/* Define if you have the ffsll function. */
#define HAVE_FFSLL 1
/* Floating point arithmetic is allowed. */
#define HAVE_FLOAT_TYPES 1
/* Define if you have the <ifaddrs.h> header file. */
#define HAVE_IFADDRS_H 1
/* Define if 'int64_t' is typedefed to 'long' at mini-os. */
#define HAVE_INT64_IS_LONG_MINIOS 1
/* Define if 'int64_t' is typedefed to 'long long' at mini-os. */
#define HAVE_INT64_IS_LONG_LONG_MINIOS 0
/* Define if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define if you have the mmap function. */
#define HAVE_MMAP 1
/* Define if you have the <net/bpf.h> header file. */
/* #undef HAVE_NET_BPF_H */
/* Define if you have the <net/if_dl.h> header file. */
/* #undef HAVE_NET_IF_DL_H */
/* Define if you have the <net/if_tap.h> header file. */
/* #undef HAVE_NET_IF_TAP_H */
/* Define if you have the <net/if_tun.h> header file. */
/* #undef HAVE_NET_IF_TUN_H */
/* Define if you have the <net/if_types.h> header file. */
/* #undef HAVE_NET_IF_TYPES_H */
/* Define if you have the <netdb.h> header file. */
#define HAVE_NETDB_H 1
/* Define if you have the <netpacket/packet.h> header file. */
#define HAVE_NETPACKET_PACKET_H 1
/* Define if <new.h> exists and works. */
/* #undef HAVE_NEW_H */
/* Define if <new> exists and works. */
#define HAVE_NEW_HDR 1
/* Placement new is always provided below. */
#define HAVE_PLACEMENT_NEW 1
/* Define if you have the random function. */
#define HAVE_RANDOM 1
/* Define if you have the snprintf function. */
#define HAVE_SNPRINTF 1
/* Define if you have the strerror function. */
#define HAVE_STRERROR 1
/* Define if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define if you have the strnlen function. */
#define HAVE_STRNLEN 1
/* Define if you have the strtof function. */
#define HAVE_STRTOF 1
/* Define if you have the strtold function. */
#define HAVE_STRTOLD 1
/* Define if you have the strtoul function. */
#define HAVE_STRTOUL 1
/* Define if you have u_intXX_t types but not uintXX_t types. */
/* #undef HAVE_U_INT_TYPES */
/* Define if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define if you have the vsnprintf function. */
#define HAVE_VSNPRINTF 1
/* The size of a `click_jiffies_t', as computed by sizeof. */
#define SIZEOF_CLICK_JIFFIES_T SIZEOF_INT
/* The size of a `off_t', as computed by sizeof. */
#define SIZEOF_OFF_T 8
/* Use portable LLRPC */
#define HAVE_PORTABLE_LLRPC 1
/* Set feature test macros before anything is included. */
#if HAVE_LARGE_FILE_SUPPORT && HAVE_INT64_TYPES
# if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS != 64
# error "bad _FILE_OFFSET_BITS, did you #include <click/config.h> first?"
# endif
# define _LARGEFILE_SOURCE 1
# define _FILE_OFFSET_BITS 64
#endif
#ifdef __APPLE__
# define _DARWIN_UNLIMITED_SELECT 1
#endif
/* Include integer type definitions. */
#ifdef HAVE_INTTYPES_H
# include <inttypes.h>
#endif
#include <sys/types.h>
/* Define uint types in terms of u_int types, if necessary. */
#ifdef HAVE_U_INT_TYPES
typedef u_int8_t uint8_t;
typedef u_int16_t uint16_t;
typedef u_int32_t uint32_t;
# ifdef HAVE_INT64_TYPES
typedef u_int64_t uint64_t;
# endif
typedef long intptr_t; /* XXX? */
typedef unsigned long uintptr_t;
#endif
/* Define HAVE_INT64_IS_LONG based on HAVE_INT64_IS_LONG_MINIOS. */
#ifdef HAVE_INT64_IS_LONG_MINIOS
# define HAVE_INT64_IS_LONG HAVE_INT64_IS_LONG_MINIOS
#endif
/* Define HAVE_INT64_IS_LONG_LONG based on HAVE_INT64_IS_LONG_LONG_MINIOS. */
#ifdef HAVE_INT64_IS_LONG_LONG_MINIOS
# define HAVE_INT64_IS_LONG_LONG HAVE_INT64_IS_LONG_LONG_MINIOS
#endif
/* If 64-bit integers exist, then 64-bit divide exists. */
#ifdef HAVE_INT64_TYPES
# define HAVE_INT64_DIVIDE 1
#endif
/* Define HAVE_USE_CLOCK_GETTIME if the clock_gettime function is usable. */
#ifndef HAVE_USE_CLOCK_GETTIME
# if HAVE_DECL_CLOCK_GETTIME && HAVE_CLOCK_GETTIME
# define HAVE_USE_CLOCK_GETTIME 1
# endif
#endif
/* Include assert macro. */
#include <assert.h>
/* Include mini-so base header */
#ifdef __cplusplus
extern "C"{
#endif
#include <mini-os/os.h>
#ifdef __cplusplus
}
#endif
/* Define if mmap is allowed. */
#if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MMAP)
# define ALLOW_MMAP 1
#endif
/* Prototype strerror if we don't have it. */
#ifndef HAVE_STRERROR
char *strerror(int errno);
#endif
/* Use nanosecond-granularity timestamps if they are enabled. */
#if HAVE_NANOTIMESTAMP_ENABLED
# define TIMESTAMP_NANOSEC 1
#endif
#ifdef __cplusplus
/* Provide placement new. */
#if HAVE_NEW_HDR
# include <new>
#elif HAVE_NEW_H
# include <new.h>
#else
inline void *operator new(size_t, void *v) { return v; }
#endif
/* Define macros that surround Click declarations. */
#ifndef CLICK_DECLS
# define CLICK_DECLS /* */
# define CLICK_ENDDECLS /* */
# define CLICK_USING_DECLS /* */
# define CLICK_NAME(name) ::name
#endif
#endif /* __cplusplus */
#endif /* CLICK_CONFIG_MINIOS_H */

View File

@ -0,0 +1,23 @@
/* include/click/config-ns.h. Generated from config-ns.h.in by configure. */
/* Process this file with configure to produce config-ns.h. -*- mode: c -*- */
#ifndef CLICK_CONFIG_NS_H
#define CLICK_CONFIG_NS_H
#ifdef __cplusplus
/* Define macros that surround Click declarations. */
#define CLICK_DECLS namespace Click {
#define CLICK_ENDDECLS }
#define CLICK_USING_DECLS using namespace Click;
#define CLICK_NAME(name) ::Click::name
#endif /* __cplusplus */
/* The ns driver probably can't use clock_gettime. */
#define HAVE_USE_CLOCK_GETTIME 0
/* Include userlevel configuration. */
#define CLICK_USERLEVEL 1
#include <click/config-userlevel.h>
#endif /* CLICK_CONFIG_NS_H */

View File

@ -0,0 +1,348 @@
/* include/click/config-userlevel.h. Generated from config-userlevel.h.in by configure. */
/* Process this file with configure to produce config-userlevel.h. -*- mode: c -*- */
#ifndef CLICK_CONFIG_USERLEVEL_H
#define CLICK_CONFIG_USERLEVEL_H
/* Define if you have the __thread storage class specifier. */
#define HAVE___THREAD_STORAGE_CLASS 1
/* Define if accept() uses socklen_t. */
#define HAVE_ACCEPT_SOCKLEN_T 1
/* Define if kqueue() may be used to wait for file descriptor events. */
#define HAVE_ALLOW_KQUEUE 1
/* Define if poll() may be used to wait for file descriptor events. */
#define HAVE_ALLOW_POLL 1
/* Define if select() may be used to wait for file descriptor events. */
#define HAVE_ALLOW_SELECT 1
/* Define if <pcap.h> uses bpf_timeval. */
/* #undef HAVE_BPF_TIMEVAL */
/* Define if you have the <byteswap.h> header file. */
#define HAVE_BYTESWAP_H 1
/* Define if you have the clock_gettime function. */
#define HAVE_CLOCK_GETTIME 1
/* Define to 1 if you have the declaration
of 'clock_gettime', and to 0 if you don't. */
#define HAVE_DECL_CLOCK_GETTIME 1
/* Define to 1 if you have the declaration
of 'madvise', and to 0 if you don't. */
#define HAVE_DECL_MADVISE 1
/* Define to 1 if you have the declaration
of 'pcap_setnonblock', and to 0 if you don't. */
#define HAVE_DECL_PCAP_SETNONBLOCK 1
/* Define if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1
/* Define if dynamic linking is possible. */
#define HAVE_DYNAMIC_LINKING 1
/* Define if you have the <execinfo.h> header file. */
#define HAVE_EXECINFO_H 1
/* Define if you have the ffs function. */
#define HAVE_FFS 1
/* Define if you have the ffsl function. */
#define HAVE_FFSL 1
/* Define if you have the ffsll function. */
#define HAVE_FFSLL 1
/* Floating point arithmetic is allowed. */
#define HAVE_FLOAT_TYPES 1
/* Define if you have the <grp.h> header file. */
#define HAVE_GRP_H 1
/* Define if the last argument to EV_SET has pointer type. */
/* #undef HAVE_EV_SET_UDATA_POINTER */
/* Define if 'struct if_data' has an 'ifi_datalen' member. */
/* #undef HAVE_IF_DATA_IFI_DATALEN */
/* Define if you have the <ifaddrs.h> header file. */
#define HAVE_IFADDRS_H 1
/* Define if 'int64_t' is typedefed to 'long' at user level. */
/* #undef HAVE_INT64_IS_LONG_USERLEVEL */
/* Define if 'int64_t' is typedefed to 'long long' at user level. */
#define HAVE_INT64_IS_LONG_LONG_USERLEVEL 1
/* Define if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define if you have the kqueue function. */
/* #undef HAVE_KQUEUE */
/* Define if your C library contains large file support. */
#define HAVE_LARGE_FILE_SUPPORT 1
/* Define if you have the <linux/if_tun.h> header file. */
#define HAVE_LINUX_IF_TUN_H 1
/* Define if you have the madvise function. */
#define HAVE_MADVISE 1
/* Define if you have the mmap function. */
#define HAVE_MMAP 1
/* Define if you have the <net/bpf.h> header file. */
/* #undef HAVE_NET_BPF_H */
/* Define if you have the <net/if_dl.h> header file. */
/* #undef HAVE_NET_IF_DL_H */
/* Define if you have the <net/if_tap.h> header file. */
/* #undef HAVE_NET_IF_TAP_H */
/* Define if you have the <net/if_tun.h> header file. */
/* #undef HAVE_NET_IF_TUN_H */
/* Define if you have the <net/if_types.h> header file. */
/* #undef HAVE_NET_IF_TYPES_H */
/* Define if you have the <netdb.h> header file. */
#define HAVE_NETDB_H 1
/* Define if you have the <net/netmap.h> header file. */
/* #undef HAVE_NET_NETMAP_H */
/* Define if you have the <netpacket/packet.h> header file. */
#define HAVE_NETPACKET_PACKET_H 1
/* Define if <new.h> exists and works. */
/* #undef HAVE_NEW_H */
/* Define if <new> exists and works. */
#define HAVE_NEW_HDR 1
/* Define if you have -lpcap and pcap.h. */
#define HAVE_PCAP 1
/* Define if you have the pcap_inject function. */
#define HAVE_PCAP_INJECT 1
/* Define if you have the pcap_sendpacket function. */
#define HAVE_PCAP_SENDPACKET 1
/* Define if you have the pcap_setdirection function. */
#define HAVE_PCAP_SETDIRECTION 1
/* Define if you have the pcap_setnonblock function. */
#define HAVE_PCAP_SETNONBLOCK 1
/* Define if you have the pcap_set_immediate_mode function. */
#define HAVE_PCAP_SET_IMMEDIATE_MODE 1
/* Define if you have -lproper and prop.h, and proper operations should be
preferred to their non-proper counterparts. */
/* #undef HAVE_PROPER */
/* Define if you have a non-emulated <poll.h> header file. */
#define HAVE_POLL_H 1
/* Define if you have the pselect function. */
#define HAVE_PSELECT 1
/* Placement new is always provided below. */
#define HAVE_PLACEMENT_NEW 1
/* Define to 1 if you have the declaration
of 'pthread_setaffinity_np', and to 0 if you don't. */
/* #undef HAVE_DECL_PTHREAD_SETAFFINITY_NP */
/* Define if you have the <pwd.h> header file. */
#define HAVE_PWD_H 1
/* Define if you have the random function. */
#define HAVE_RANDOM 1
/* Define if you have the sigaction function. */
#define HAVE_SIGACTION 1
/* Define if you have the snprintf function. */
#define HAVE_SNPRINTF 1
/* Define if 'struct sockaddr_in' has a 'sin_len' member. */
/* #undef HAVE_SOCKADDR_IN_SIN_LEN */
/* Define if you have the strerror function. */
#define HAVE_STRERROR 1
/* Define if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define if you have the strnlen function. */
#define HAVE_STRNLEN 1
/* Define if you have the strtof function. */
#define HAVE_STRTOF 1
/* Define if you have the strtold function. */
#define HAVE_STRTOLD 1
/* Define if you have the strtoul function. */
#define HAVE_STRTOUL 1
/* Define if you have the <sys/event.h> header file. */
/* #undef HAVE_SYS_EVENT_H */
/* Define if you have the <sys/mman.h> header file. */
#define HAVE_SYS_MMAN_H 1
/* Define if you have the tcgetpgrp function. */
#define HAVE_TCGETPGRP 1
/* Define if you have the <termio.h> header file. */
#define HAVE_TERMIO_H 1
/* Define if you have u_intXX_t types but not uintXX_t types. */
/* #undef HAVE_U_INT_TYPES */
/* Define if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define if a Click user-level driver might run multiple threads. */
/* #undef HAVE_USER_MULTITHREAD */
/* Define if a Click user-level driver uses Intel DPDK. */
/* #undef HAVE_DPDK */
/* Define if Click should use Valgrind client requests. */
/* #undef HAVE_VALGRIND */
/* Define if you have the <valgrind/memcheck.h> header file. */
/* #undef HAVE_VALGRIND_MEMCHECK_H */
/* Define if you have the vsnprintf function. */
#define HAVE_VSNPRINTF 1
/* The size of a `click_jiffies_t', as computed by sizeof. */
#define SIZEOF_CLICK_JIFFIES_T SIZEOF_INT
/* The size of a `off_t', as computed by sizeof. */
#define SIZEOF_OFF_T 8
/* Set feature test macros before anything is included. */
#if HAVE_LARGE_FILE_SUPPORT && HAVE_INT64_TYPES
# if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS != 64
# error "bad _FILE_OFFSET_BITS, did you #include <click/config.h> first?"
# endif
# define _LARGEFILE_SOURCE 1
# define _FILE_OFFSET_BITS 64
#endif
#ifdef __APPLE__
# define _DARWIN_UNLIMITED_SELECT 1
#endif
/* Include integer type definitions. */
#ifdef HAVE_INTTYPES_H
# include <inttypes.h>
#endif
#include <sys/types.h>
/* Define uint types in terms of u_int types, if necessary. */
#ifdef HAVE_U_INT_TYPES
typedef u_int8_t uint8_t;
typedef u_int16_t uint16_t;
typedef u_int32_t uint32_t;
# ifdef HAVE_INT64_TYPES
typedef u_int64_t uint64_t;
# endif
typedef long intptr_t; /* XXX? */
typedef unsigned long uintptr_t;
#endif
/* Define HAVE_INT64_IS_LONG based on HAVE_INT64_IS_LONG_USERLEVEL. */
#ifdef HAVE_INT64_IS_LONG_USERLEVEL
# define HAVE_INT64_IS_LONG HAVE_INT64_IS_LONG_USERLEVEL
#endif
/* Define HAVE_INT64_IS_LONG_LONG based on HAVE_INT64_IS_LONG_LONG_USERLEVEL. */
#ifdef HAVE_INT64_IS_LONG_LONG_USERLEVEL
# define HAVE_INT64_IS_LONG_LONG HAVE_INT64_IS_LONG_LONG_USERLEVEL
#endif
/* If 64-bit integers exist, then 64-bit divide exists. */
#ifdef HAVE_INT64_TYPES
# define HAVE_INT64_DIVIDE 1
#endif
/* Define HAVE_MULTITHREAD based on HAVE_USER_MULTITHREAD. */
#ifdef HAVE_USER_MULTITHREAD
# define HAVE_MULTITHREAD HAVE_USER_MULTITHREAD
#endif
/* Define HAVE_USE_CLOCK_GETTIME if the clock_gettime function is usable. */
#ifndef HAVE_USE_CLOCK_GETTIME
# if HAVE_DECL_CLOCK_GETTIME && HAVE_CLOCK_GETTIME
# define HAVE_USE_CLOCK_GETTIME 1
# endif
#endif
/* Include assert macro. */
#include <assert.h>
/* Define likely and unlikely macros. */
#if __GNUC__ >= 3
# define likely(x) __builtin_expect(!!(x), 1)
# define unlikely(x) __builtin_expect(!!(x), 0)
#else
# define likely(x) (x)
# define unlikely(x) (x)
#endif
/* Define if mmap is allowed. */
#if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MMAP)
# define ALLOW_MMAP 1
#endif
/* Prototype strerror if we don't have it. */
#ifndef HAVE_STRERROR
char *strerror(int errno);
#endif
/* Use nanosecond-granularity timestamps if they are enabled. */
#if HAVE_NANOTIMESTAMP_ENABLED
# define TIMESTAMP_NANOSEC 1
# define HAVE_NANOTIMESTAMP 1 /* Deprecated */
#endif
#ifdef __cplusplus
/* Provide placement new. */
#if HAVE_NEW_HDR
# include <new>
#elif HAVE_NEW_H
# include <new.h>
#else
inline void *operator new(size_t, void *v) { return v; }
#endif
/* Prototype madvise if we have it, but not the prototype. */
#if ALLOW_MMAP && HAVE_MADVISE && !HAVE_DECL_MADVISE
extern "C" int madvise(void *addr, size_t len, int behav);
#endif
/* Define macros that surround Click declarations. */
#ifndef CLICK_DECLS
# define CLICK_DECLS /* */
# define CLICK_ENDDECLS /* */
# define CLICK_USING_DECLS /* */
# define CLICK_NAME(name) ::name
#endif
#endif /* __cplusplus */
#endif /* CLICK_CONFIG_USERLEVEL_H */

View File

@ -0,0 +1,333 @@
/* include/click/config.h. Generated from config.h.in by configure. */
/* Process this file with configure to produce config.h. -*- mode: c -*- */
#ifndef CLICK_CONFIG_H
#define CLICK_CONFIG_H
/* Define to 1 if type `char' is unsigned and you are not using gcc. */
#ifndef __CHAR_UNSIGNED__
/* # undef __CHAR_UNSIGNED__ */
#endif
#define CLICK_BIG_ENDIAN 4321
#define CLICK_LITTLE_ENDIAN 1234
#define CLICK_NO_ENDIAN 0
/* Define to byte order of target machine. */
#define CLICK_BYTE_ORDER CLICK_LITTLE_ENDIAN
/* Define to enable debugging support for Click scheduling. */
/* #undef CLICK_DEBUG_SCHEDULING */
/* Define for Click memory allocation debugging. */
/* #undef CLICK_DMALLOC */
/* Define to generate smaller object files. */
/* #undef CLICK_OPTIMIZE_SIZE */
/* Version number of package */
#define CLICK_VERSION "2.1"
/* Version number of package, in CLICK_MAKE_VERSION_CODE format */
#define CLICK_VERSION_CODE CLICK_MAKE_VERSION_CODE(2,1,0)
/* Define to desired statistics level. */
#define CLICK_STATS 0
/* Define if PollDevice should run fast to get good benchmark numbers */
/* #undef CLICK_WARP9 */
/* Define if you have the __builtin_clz function. */
#define HAVE___BUILTIN_CLZ 1
/* Define if you have the __builtin_clzl function. */
#define HAVE___BUILTIN_CLZL 1
/* Define if you have the __builtin_clzll function. */
#define HAVE___BUILTIN_CLZLL 1
/* Define if you have the __builtin_ffs function. */
#define HAVE___BUILTIN_FFS 1
/* Define if you have the __builtin_ffsl function. */
#define HAVE___BUILTIN_FFSL 1
/* Define if you have the __builtin_ffsll function. */
#define HAVE___BUILTIN_FFSLL 1
/* Define if you have the __has_trivial_copy compiler intrinsic. */
#define HAVE___HAS_TRIVIAL_COPY 1
/* Define if you have the __sync_synchronize function. */
#define HAVE___SYNC_SYNCHRONIZE 1
/* Define if the __sync_synchronize function supports arguments. */
/* #undef HAVE___SYNC_SYNCHRONIZE_ARGUMENTS */
/* Define if the va_list type is addressable. */
#define HAVE_ADDRESSABLE_VA_LIST 1
/* Define if right shift of signed integers acts by sign extension. */
#define HAVE_ARITHMETIC_RIGHT_SHIFT 1
/* Define if Port::push/Port::pull should use bound function pointers. */
/* #undef HAVE_BOUND_PORT_TRANSFER */
/* Define if the C++ compiler understands constexpr. */
#define HAVE_CXX_CONSTEXPR 1
/* Define if the C++ compiler understands #pragma interface. */
#define HAVE_CXX_PRAGMA_INTERFACE 1
/* Define if the C++ compiler understands rvalue references. */
#define HAVE_CXX_RVALUE_REFERENCES 1
/* Define if the C++ compiler understands static_assert. */
#define HAVE_CXX_STATIC_ASSERT 1
/* Define if the C++ compiler understands template alias. */
#define HAVE_CXX_TEMPLATE_ALIAS 1
/* Define if the machine is indifferent to alignment. */
#define HAVE_INDIFFERENT_ALIGNMENT 1
/* Define if you want to use Intel-specific instructions. */
/* #undef HAVE_INTEL_CPU */
/* Define if 64-bit integer types are enabled. */
#define HAVE_INT64_TYPES 1
/* Define if IPv6 support is enabled. */
/* #undef HAVE_IP6 */
/* Define if IPsec support is enabled. */
/* #undef HAVE_IPSEC */
/* Define to 1 if the system has the type `long long'. */
#define HAVE_LONG_LONG 1
/* Define if nanosecond-granularity timestamps are enabled. */
#define HAVE_NANOTIMESTAMP_ENABLED 1
/* Define if you want to use the stride scheduler. */
#define HAVE_STRIDE_SCHED 1
/* Define to 1 since we have Strings. */
#define HAVE_STRING 1
/* Define to 1 if the system has the type `struct timespec'. */
#define HAVE_STRUCT_TIMESPEC 1
#ifdef HAVE_STRIDE_SCHED
/* Define if you want task scheduling to use a heap, not a linked list. */
/* #undef HAVE_TASK_HEAP */
#endif
/* The size of a `int', as computed by sizeof. */
#define SIZEOF_INT 4
/* The size of a `long', as computed by sizeof. */
#define SIZEOF_LONG 4
/* The size of a `long long', as computed by sizeof. */
#define SIZEOF_LONG_LONG 8
/* The size of a `size_t', as computed by sizeof. */
#define SIZEOF_SIZE_T 4
/* The size of a `struct timespec', as computed by sizeof. */
#define SIZEOF_STRUCT_TIMESPEC 8
/* The size of a `struct timeval', as computed by sizeof. */
#define SIZEOF_STRUCT_TIMEVAL 8
/* The size of a `ptrdiff_t', as computed by sizeof. */
#define SIZEOF_PTRDIFF_T 4
/* The size of a `void *', as computed by sizeof. */
#define SIZEOF_VOID_P 4
/* Define if you want to run multithreaded Click. */
/* #undef __MTCLICK__ */
/* Define inline, if necessary. C only. */
#ifndef __cplusplus
/* #undef inline */
#endif
/* Define constexpr to const under C or old C++. */
#if !defined(__cplusplus) || !HAVE_CXX_CONSTEXPR
# define constexpr const
#endif
/* Define CLICK_DEBUG_SCHEDULING to 0 if disabled. */
#ifndef CLICK_DEBUG_SCHEDULING
# define CLICK_DEBUG_SCHEDULING 0
#endif
/* Define macro for creating Click version codes (a la Linux version codes). */
#define CLICK_MAKE_VERSION_CODE(major, minor, patch) \
(((major) << 16) | ((minor) << 8) | (patch))
/* Define macro for aligning variables. */
#if __GNUC__
# define CLICK_ALIGNED(x) __attribute__((aligned(x)))
#else
# define CLICK_ALIGNED(x) /* nothing */
#endif
/* Define macro for size of a cache line. */
#define CLICK_CACHE_LINE_SIZE 64
/* Define macro for the difference between 'x' and the next higher multiple
of CLICK_CACHE_LINE_SIZE (between 0 and CLICK_CACHE_LINE_SIZE - 1). */
#define CLICK_CACHE_LINE_PAD_BYTES(x) \
((((x) + CLICK_CACHE_LINE_SIZE - 1) / CLICK_CACHE_LINE_SIZE) * CLICK_CACHE_LINE_SIZE - (x))
/* Define macro for deprecated functions. */
#if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ == 0)
# define CLICK_DEPRECATED /* nothing */
#else
# define CLICK_DEPRECATED __attribute__((deprecated))
#endif
/* Define macro for deprecated functions with message. */
#if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ == 0)
# define CLICK_DEPRECATED_MSG(m) /* nothing */
#elif __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ <= 4)
# define CLICK_DEPRECATED_MSG(m) __attribute__((deprecated))
#else
# define CLICK_DEPRECATED_MSG(m) __attribute__((deprecated(m)))
#endif
/* Define macro for deprecated enumerations. */
#if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 4)
# define CLICK_DEPRECATED_ENUM /* nothing */
#else
# define CLICK_DEPRECATED_ENUM __attribute__((deprecated))
#endif
/* Define macros for marking types as may-alias. */
#if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 3)
# define CLICK_MAY_ALIAS /* nothing */
#else
# define CLICK_MAY_ALIAS __attribute__((__may_alias__))
#endif
/* Define macro for marking functions noninlinable. */
#ifdef CLICK_LINUXMODULE
# define CLICK_NOINLINE noinline
#elif __GNUC__
# define CLICK_NOINLINE __attribute__((noinline))
#else
# define CLICK_NOINLINE /* nothing */
#endif
/* Define macro for funtions that should be inline-able even if compiling without optimization. */
#if __GNUC__
# define CLICK_ALWAYS_INLINE __attribute__((always_inline))
#else
# define CLICK_ALWAYS_INLINE /* nothing */
#endif
/* Define macros for declaring packed structures. */
#ifdef __GNUC__
# define CLICK_PACKED_STRUCTURE(open, close) open close __attribute__((packed))
# define CLICK_SIZE_PACKED_STRUCTURE(open, close) open close __attribute__((packed)) /* deprecated */
# define CLICK_SIZE_PACKED_ATTRIBUTE __attribute__((packed))
#else
# define CLICK_PACKED_STRUCTURE(open, close) _Cannot_pack_structure__Use_GCC
# define CLICK_SIZE_PACKED_STRUCTURE(open, close) open close /* deprecated */
# define CLICK_SIZE_PACKED_ATTRIBUTE
#endif
/* Define macro for functions whose results should not be ignored. */
#if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 4)
# define CLICK_WARN_UNUSED_RESULT /* nothing */
#else
# define CLICK_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
#endif
/* Define macro for cold (rarely used) functions. */
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3)
# define CLICK_COLD /* nothing */
#else
# define CLICK_COLD __attribute__((cold))
#endif
/* Define ARCH_IS_BIG_ENDIAN based on CLICK_BYTE_ORDER. */
#if CLICK_BYTE_ORDER == CLICK_BIG_ENDIAN
# define ARCH_IS_BIG_ENDIAN 1
#elif CLICK_BYTE_ORDER == CLICK_LITTLE_ENDIAN
# define ARCH_IS_BIG_ENDIAN 0
#endif
/* Define macro for htons() on constants (allows htons() in switch cases). */
#if CLICK_BYTE_ORDER == CLICK_BIG_ENDIAN
# define click_constant_htons(x) (x)
#elif CLICK_BYTE_ORDER == CLICK_LITTLE_ENDIAN
# define click_constant_htons(x) ((((x) >> 8) & 255) | (((x) & 255) << 8))
#endif
/* EXPORT_ELEMENT, ELEMENT_REQUIRES, ELEMENT_PROVIDES, ELEMENT_HEADER,
ELEMENT_LIBS, and ELEMENT_MT_SAFE are noops. */
#define EXPORT_ELEMENT(x)
#define ELEMENT_REQUIRES(x)
#define ELEMENT_PROVIDES(x)
#define ELEMENT_HEADER(x)
#define ELEMENT_LIBS(x)
#define ELEMENT_MT_SAFE(x)
/* Assume CLICK_USERLEVEL unless otherwise defined. */
#if !defined(CLICK_USERLEVEL) && !defined(CLICK_TOOL) && !defined(CLICK_LINUXMODULE) && !defined(CLICK_BSDMODULE) && !defined(CLICK_MINIOS)
# define CLICK_USERLEVEL 1
#endif
/* Define stuff under a Linux module. */
#ifdef CLICK_LINUXMODULE
# include <click/config-linuxmodule.h>
#endif
/* Define stuff under a FreeBSD module. */
#ifdef CLICK_BSDMODULE
# include <click/config-bsdmodule.h>
#endif
/* Define stuff under nsclick. */
#ifdef CLICK_NS
# include <click/config-ns.h>
#endif
/* Define stuff under tools or a user-level driver. */
#if defined(CLICK_USERLEVEL) || defined(CLICK_TOOL)
# include <click/config-userlevel.h>
#endif
/* Define stuff under a MiniOS application. */
#ifdef CLICK_MINIOS
# include <click/config-minios.h>
#endif
/* Ensure declaration of DefaultArg template. */
#ifdef __cplusplus
CLICK_DECLS
template <typename T> struct DefaultArg;
/** @class uninitialized_type
@brief Type tag indicating an object should not be initialized. */
struct uninitialized_type {
};
CLICK_ENDDECLS
#endif
/* Define aliasing versions of integer and pointer types. */
typedef uint16_t click_aliasable_uint16_t CLICK_MAY_ALIAS;
typedef int16_t click_aliasable_int16_t CLICK_MAY_ALIAS;
typedef uint32_t click_aliasable_uint32_t CLICK_MAY_ALIAS;
typedef int32_t click_aliasable_int32_t CLICK_MAY_ALIAS;
#if HAVE_INT64_TYPES
typedef uint64_t click_aliasable_uint64_t CLICK_MAY_ALIAS;
typedef int64_t click_aliasable_int64_t CLICK_MAY_ALIAS;
#endif
typedef void *click_aliasable_void_pointer_t CLICK_MAY_ALIAS;
#endif /* CLICK_CONFIG_H */

View File

@ -0,0 +1,743 @@
// -*- c-basic-offset: 4; related-file-name: "../../lib/confparse.cc" -*-
#ifndef CLICK_CONFPARSE_HH
#define CLICK_CONFPARSE_HH
/// @cond never
#include <click/string.hh>
#include <click/vector.hh>
struct in_addr;
#if HAVE_IP6
struct in6_addr;
#endif
CLICK_DECLS
class ErrorHandler;
class StringAccum;
class Timestamp;
#ifndef CLICK_TOOL
class Element;
class Router;
class Handler;
class HandlerCall;
# define CP_VA_PARSE_ARGS_REST const Element*, ErrorHandler*, ...
# define CP_OPT_CONTEXT , const Element* context = 0
# define CP_CONTEXT , const Element* context
# define CP_PASS_CONTEXT , context
#else
# define CP_VA_PARSE_ARGS_REST ErrorHandler*, ...
# define CP_OPT_CONTEXT
# define CP_CONTEXT
# define CP_PASS_CONTEXT
#endif
#ifndef CLICK_COMPILING_CONFPARSE_CC
# define CLICK_CONFPARSE_DEPRECATED CLICK_DEPRECATED
#else
# define CLICK_CONFPARSE_DEPRECATED /* */
#endif
#if __GNUC__ <= 3
# define CP_SENTINEL
#else
# define CP_SENTINEL __attribute__((sentinel))
#endif
/// @endcond
/// @name Argument Manipulation
//@{
const char* cp_skip_space(const char* begin, const char* end);
const char* cp_skip_comment_space(const char* begin, const char* end);
const char* cp_skip_double_quote(const char* begin, const char* end);
bool cp_eat_space(String &str);
inline bool cp_is_space(const String &str);
bool cp_is_word(const String &str);
bool cp_is_click_id(const String &str);
String cp_uncomment(const String &str);
String cp_unquote(const String &str);
const char* cp_process_backslash(const char* begin, const char* end, StringAccum &sa);
String cp_quote(const String &str, bool allow_newlines = false);
void cp_argvec(const String& str, Vector<String>& conf);
String cp_unargvec(const Vector<String>& conf);
void cp_spacevec(const String& str, Vector<String>& conf);
/// @brief Remove and return the first space-separated argument from @a str.
/// @param[in,out] str space-separated configuration string
///
/// The first space-separated argument in the configuration string is removed
/// and returned. The returned argument is passed through cp_uncomment(). @a
/// str is set to the remaining portion of the string, with any preceding
/// spaces and comments removed. If the input string is all spaces and
/// comments, then both the returned string and @a str will be empty.
String cp_shift_spacevec(String &str);
String cp_unspacevec(const String *begin, const String *end);
inline String cp_unspacevec(const Vector<String> &conf);
//@}
/// @name Direct Parsing Functions
//@{
enum CpErrors {
CPE_OK = 0,
CPE_FORMAT,
CPE_NEGATIVE,
CPE_OVERFLOW,
CPE_INVALID,
CPE_MEMORY,
CPE_NOUNITS
};
extern int cp_errno;
// strings and words
bool cp_string(const String& str, String* result, String *rest = 0);
bool cp_word(const String& str, String* result, String *rest = 0);
bool cp_keyword(const String& str, String* result, String *rest = 0);
bool cp_bool(const String& str, bool* result);
// numbers
enum { cp_basic_integer_whole = 64 };
const char *cp_basic_integer(const char *begin, const char *end, int flags, int size, void *result);
inline const char *cp_integer(const char *begin, const char *end, int base, int *result);
inline const char *cp_integer(const char *begin, const char *end, int base, unsigned *result);
inline const char *cp_integer(const char *begin, const char *end, int base, long *result);
inline const char *cp_integer(const char *begin, const char *end, int base, unsigned long *result);
/// @cond never
inline const unsigned char *cp_integer(const unsigned char *begin, const unsigned char *end, int base, unsigned *result);
inline const unsigned char *cp_integer(const unsigned char *begin, const unsigned char *end, int base, unsigned long *result);
/// @endcond
#if HAVE_LONG_LONG
inline const char *cp_integer(const char *begin, const char *end, int base, long long *result);
inline const char *cp_integer(const char *begin, const char *end, int base, unsigned long long *result);
/// @cond never
inline const unsigned char *cp_integer(const unsigned char *begin, const unsigned char *end, int base, unsigned long long *result);
/// @endcond
#elif HAVE_INT64_TYPES && !HAVE_INT64_IS_LONG
inline const char *cp_integer(const char *begin, const char *end, int base, int64_t *result);
inline const char *cp_integer(const char *begin, const char *end, int base, uint64_t *result);
/// @cond never
inline const unsigned char *cp_integer(const unsigned char *begin, const unsigned char *end, int base, uint64_t *result);
/// @endcond
#endif
inline bool cp_integer(const String &str, int base, int *result);
inline bool cp_integer(const String &str, int base, unsigned int *result);
inline bool cp_integer(const String &str, int base, long *result);
inline bool cp_integer(const String &str, int base, unsigned long *result);
#if HAVE_LONG_LONG
inline bool cp_integer(const String &str, int base, long long *result);
inline bool cp_integer(const String &str, int base, unsigned long long *result);
#elif HAVE_INT64_TYPES && !HAVE_INT64_IS_LONG
inline bool cp_integer(const String &str, int base, int64_t *result);
inline bool cp_integer(const String &str, int base, uint64_t *result);
#endif
inline bool cp_integer(const String &str, int *result);
inline bool cp_integer(const String &str, unsigned int *result);
inline bool cp_integer(const String &str, long *result);
inline bool cp_integer(const String &str, unsigned long *result);
#if HAVE_LONG_LONG
inline bool cp_integer(const String &str, long long *result);
inline bool cp_integer(const String &str, unsigned long long *result);
#elif HAVE_INT64_TYPES && !HAVE_INT64_IS_LONG
inline bool cp_integer(const String &str, int64_t *result);
inline bool cp_integer(const String &str, uint64_t *result);
#endif
#define CP_REAL2_MAX_FRAC_BITS 28
bool cp_real2(const String& str, int frac_bits, int32_t* result);
bool cp_real2(const String& str, int frac_bits, uint32_t* result);
bool cp_real10(const String& str, int frac_digits, int32_t* result);
bool cp_real10(const String& str, int frac_digits, uint32_t* result);
bool cp_real10(const String& str, int frac_digits, uint32_t* result_int, uint32_t* result_frac);
#if HAVE_FLOAT_TYPES
bool cp_double(const String& str, double* result);
#endif
bool cp_seconds_as(const String& str, int frac_digits, uint32_t* result);
bool cp_seconds_as_milli(const String& str, uint32_t* result);
bool cp_seconds_as_micro(const String& str, uint32_t* result);
#if HAVE_FLOAT_TYPES
bool cp_seconds(const String& str, double* result);
#endif
bool cp_time(const String &str, Timestamp *result, bool allow_negative = false);
bool cp_time(const String& str, struct timeval* result);
bool cp_bandwidth(const String& str, uint32_t* result);
// network addresses
class IPAddressList;
bool cp_ip_address(const String& str, IPAddress* result CP_OPT_CONTEXT);
inline bool cp_ip_address(const String& str, struct in_addr* result CP_OPT_CONTEXT);
bool cp_ip_address(const String& str, unsigned char* result CP_OPT_CONTEXT);
bool cp_ip_prefix(const String& str, IPAddress* result_addr, IPAddress* result_mask, bool allow_bare_address CP_OPT_CONTEXT);
bool cp_ip_prefix(const String& str, unsigned char* result_addr, unsigned char* result_mask, bool allow_bare_address CP_OPT_CONTEXT);
bool cp_ip_prefix(const String& str, IPAddress* result_addr, IPAddress* result_mask CP_OPT_CONTEXT);
bool cp_ip_prefix(const String& str, unsigned char* result_addr, unsigned char* result_mask CP_OPT_CONTEXT);
bool cp_ip_address_list(const String& str, Vector<IPAddress>* result CP_OPT_CONTEXT);
#if HAVE_IP6
class IP6Address;
bool cp_ip6_address(const String& str, IP6Address* result CP_OPT_CONTEXT);
inline bool cp_ip6_address(const String& str, struct in6_addr* result CP_OPT_CONTEXT);
bool cp_ip6_address(const String& str, unsigned char* result CP_OPT_CONTEXT);
bool cp_ip6_prefix(const String& str, IP6Address* result_addr, int* result_prefix, bool allow_bare_address CP_OPT_CONTEXT);
bool cp_ip6_prefix(const String& str, unsigned char* result_addr, int* result_prefix, bool allow_bare_address CP_OPT_CONTEXT);
bool cp_ip6_prefix(const String& str, unsigned char* result_addr, unsigned char* result_mask, bool allow_bare_address CP_OPT_CONTEXT);
bool cp_ip6_prefix(const String& str, IP6Address* result_addr, IP6Address* result_mask, bool allow_bare_address CP_OPT_CONTEXT);
#endif
class EtherAddress;
bool cp_ethernet_address(const String& str, EtherAddress* result CP_OPT_CONTEXT);
bool cp_ethernet_address(const String& str, unsigned char* result CP_OPT_CONTEXT);
bool cp_tcpudp_port(const String& str, int proto, uint16_t* result CP_OPT_CONTEXT);
#if !CLICK_TOOL
Element *cp_element(const String &str, const Element *context, ErrorHandler *errh = 0, const char *argname = 0);
Element *cp_element(const String &str, Router *router, ErrorHandler *errh = 0, const char *argname = 0);
bool cp_handler_name(const String& str, Element** result_element, String* result_hname, const Element* context, ErrorHandler* errh=0);
bool cp_handler(const String& str, int flags, Element** result_element, const Handler** result_handler, const Element* context, ErrorHandler* errh=0);
#endif
#if CLICK_USERLEVEL || CLICK_TOOL
bool cp_filename(const String& str, String* result);
bool cp_file_offset(const String& str, off_t* result);
#endif
#if !CLICK_TOOL
bool cp_anno(const String &str, int size, int *result CP_OPT_CONTEXT);
#endif
//@}
/// @name cp_va_kparse
//@{
int cp_va_kparse(const Vector<String>& conf, CP_VA_PARSE_ARGS_REST) CP_SENTINEL;
int cp_va_kparse(const String& str, CP_VA_PARSE_ARGS_REST) CP_SENTINEL;
int cp_va_space_kparse(const String& str, CP_VA_PARSE_ARGS_REST) CP_SENTINEL;
int cp_va_kparse_keyword(const String& str, CP_VA_PARSE_ARGS_REST) CP_SENTINEL;
int cp_va_kparse_remove_keywords(Vector<String>& conf, CP_VA_PARSE_ARGS_REST) CP_SENTINEL;
int cp_assign_arguments(const Vector<String> &argv, const String *param_begin, const String *param_end, Vector<String>* values = 0);
void cp_va_static_initialize();
void cp_va_static_cleanup();
/// @brief Type of flags for cp_va_kparse() items.
enum CpKparseFlags {
cpkN = 0, ///< Default flags
cpkM = 1, ///< Argument is mandatory
cpkP = 2, ///< Argument may be specified positionally
cpkC = 4, ///< Argument presence should be confirmed
cpkD = 8, ///< Argument is deprecated
cpkNormal = cpkN,
cpkMandatory = cpkM,
cpkPositional = cpkP,
cpkConfirm = cpkC,
cpkDeprecated = cpkD
};
/// @brief Type of argument type names for cp_va_kparse() items.
typedef const char *CpVaParseCmd;
extern const CpVaParseCmd
cpEnd, ///< Use as argument name. Ends cp_va argument list.
cpIgnoreRest, ///< Use as argument name. No result storage; causes cp_va_kparse() to ignore unparsed arguments and any remaining items.
cpIgnore, ///< No result storage, ignores this argument.
cpArgument, ///< Result storage String*, accepts any argument.
cpArguments, ///< Result storage Vector<String>*, accepts any number of arguments with the same keyword.
cpString, ///< Result storage String*, parsed by cp_string().
cpWord, ///< Result storage String*, parsed by cp_word().
cpKeyword, ///< Result storage String*, parsed by cp_keyword().
cpBool, ///< Result storage bool*, parsed by cp_bool().
cpByte, ///< Result storage unsigned char*, parsed by cp_integer().
cpShort, ///< Result storage short*, parsed by cp_integer().
cpUnsignedShort, ///< Result storage unsigned short*, parsed by cp_integer().
cpInteger, ///< Result storage int32_t*, parsed by cp_integer().
cpUnsigned, ///< Result storage uint32_t*, parsed by cp_integer().
cpSize, ///< Result storage size_t*, parsed by cp_integer().
cpNamedInteger, ///< Parse parameter uint32_t nameinfo_type, result storage int32_t*, parsed by NameInfo::query_int.
#if HAVE_INT64_TYPES
cpInteger64, ///< Result storage int64_t*, parsed by cp_integer().
cpUnsigned64, ///< Result storage uint64_t*, parsed by cp_integer().
#endif
cpUnsignedReal2, ///< Parse parameter int frac_bits, result storage uint32_t*, parsed by cp_real2().
cpReal10, ///< Parse parameter int frac_digits, result storage int32_t*, parsed by cp_real10().
cpUnsignedReal10, ///< Parse parameter int frac_digits, result storage uint32_t*, parsed by cp_real10().
#if HAVE_FLOAT_TYPES
cpDouble, ///< Result storage double*, parsed by cp_double().
#endif
cpSeconds, ///< Result storage uint32_t*, parsed by cp_seconds_as() with frac_digits 0.
cpSecondsAsMilli, ///< Result storage uint32_t*, parsed by cp_seconds_as_milli().
cpSecondsAsMicro, ///< Result storage uint32_t*, parsed by cp_seconds_as_micro().
cpTimestamp, ///< Result storage Timestamp*, parsed by cp_time().
cpTimestampSigned, ///< Result storage Timestamp*, parsed by cp_time().
cpTimeval, ///< Result storage struct timeval*, parsed by cp_time().
cpBandwidth, ///< Result storage uint32_t*, parsed by cp_bandwidth().
cpIPAddress, ///< Result storage IPAddress* or equivalent, parsed by cp_ip_address().
cpIPPrefix, ///< Result storage IPAddress* addr and IPAddress *mask, parsed by cp_ip_prefix().
cpIPAddressOrPrefix,///< Result storage IPAddress* addr and IPAddress *mask, parsed by cp_ip_prefix().
cpIPAddressList, ///< Result storage Vector<IPAddress>*, parsed by cp_ip_address_list().
cpEtherAddress, ///< Result storage EtherAddress*, parsed by cp_ethernet_address().
cpEthernetAddress, ///< Result storage EtherAddress*, parsed by cp_ethernet_address(). Synonym for cpEtherAddress.
cpTCPPort, ///< Result storage uint16_t*, parsed by cp_tcpudp_port().
cpUDPPort, ///< Result storage uint16_t*, parsed by cp_tcpudp_port().
cpElement, ///< Result storage Element**, parsed by cp_element().
cpElementCast, ///< Parse parameter const char*, result storage void**, parsed by cp_element() and Element::cast().
cpHandlerName, ///< Result storage Element** and String*, parsed by cp_handler_name().
cpHandlerCallRead, ///< Result storage HandlerCall*, parsed by HandlerCall.
cpHandlerCallWrite, ///< Result storage HandlerCall*, parsed by HandlerCall.
cpHandlerCallPtrRead, ///< Result storage HandlerCall**, parsed by HandlerCall::reset_read.
cpHandlerCallPtrWrite, ///< Result storage HandlerCall**, parsed by HandlerCall::reset_write.
cpIP6Address, ///< Result storage IP6Address* or equivalent, parsed by cp_ip6_address().
cpIP6Prefix, ///< Result storage IP6Address* addr and IP6Address* mask, parsed by cp_ip6_prefix().
cpIP6PrefixLen, ///< Result storage IP6Address* addr and int* prefix_len, parsed by cp_ip6_prefix().
cpIP6AddressOrPrefix,///< Result storage IP6Address* addr and IP6Address* mask, parsed by cp_ip6_prefix().
#if CLICK_USERLEVEL || CLICK_TOOL
cpFilename, ///< Result storage String*, parsed by cp_filename().
cpFileOffset, ///< Result storage off_t*, parsed by cp_integer().
#endif
#if !CLICK_TOOL
cpAnno, ///< Parse parameter int annotation_size, result storage int*, parsed by cp_anno().
#endif
cpOptional, ///< cp_va_parse only: Following arguments are optional.
cpKeywords, ///< cp_va_parse only: Following arguments are keywords.
cpConfirmKeywords, ///< cp_va_parse only: Following arguments are confirmed keywords.
cpMandatoryKeywords;///< cp_va_parse only: Following arguments are mandatory keywords.
// old names, here for compatibility:
extern const CpVaParseCmd
cpInterval CLICK_CONFPARSE_DEPRECATED, // struct timeval*
cpReadHandlerCall CLICK_CONFPARSE_DEPRECATED, // HandlerCall**
cpWriteHandlerCall CLICK_CONFPARSE_DEPRECATED; // HandlerCall**
//@}
/// @name Unparsing
//@{
String cp_unparse_bool(bool value);
String cp_unparse_real2(int32_t value, int frac_bits);
String cp_unparse_real2(uint32_t value, int frac_bits);
#if HAVE_INT64_TYPES
String cp_unparse_real2(int64_t value, int frac_bits);
String cp_unparse_real2(uint64_t value, int frac_bits);
#endif
String cp_unparse_real10(int32_t value, int frac_digits);
String cp_unparse_real10(uint32_t value, int frac_digits);
String cp_unparse_milliseconds(uint32_t value);
String cp_unparse_microseconds(uint32_t value);
String cp_unparse_interval(const Timestamp& value) CLICK_DEPRECATED;
String cp_unparse_interval(const struct timeval& value) CLICK_DEPRECATED;
String cp_unparse_bandwidth(uint32_t value);
//@}
/// @name Legacy Functions
//@{
int cp_va_parse(const Vector<String>& conf, CP_VA_PARSE_ARGS_REST) CLICK_DEPRECATED;
int cp_va_parse(const String& str, CP_VA_PARSE_ARGS_REST) CLICK_DEPRECATED;
int cp_va_space_parse(const String& str, CP_VA_PARSE_ARGS_REST) CLICK_DEPRECATED;
int cp_va_parse_keyword(const String& str, CP_VA_PARSE_ARGS_REST) CLICK_DEPRECATED;
int cp_va_parse_remove_keywords(Vector<String>& conf, int first, CP_VA_PARSE_ARGS_REST) CLICK_DEPRECATED;
// Argument syntax:
// cp_va_arg ::= cpEnd // terminates argument list (not 0!)
// | cpOptional | cpKeywords | cpIgnore... // manipulators
// | CpVaParseCmd cmd, const char *description,
// [Optional Helpers], Results
// // Helpers and Results depend on 'cmd';
// // see table above
// | const char *keyword, CpVaParseCmd cmd, const char *description,
// [Optional Helpers], Results
// // keyword argument, within cpKeywords or
// // cpMandatoryKeywords
// | const char *keyword, CpVaParseCmd cmd, const char *description,
// bool *keyword_given, [Optional Helpers], Results
// // keyword argument, within cpConfirmKeywords
// Returns the number of result arguments set, or negative on error.
// Stores no values in the result arguments on error.
//@}
/// @name Argument Types for cp_va_kparse()
//@{
struct cp_value;
struct cp_argtype;
typedef void (*cp_parsefunc)(cp_value* value, const String& arg,
ErrorHandler* errh, const char* argdesc CP_CONTEXT);
typedef void (*cp_storefunc)(cp_value* value CP_CONTEXT);
struct cp_argtype {
const char* name;
cp_argtype* next;
cp_parsefunc parse;
cp_storefunc store;
void* user_data;
int flags;
const char* description;
int internal;
int use_count;
};
struct cp_value {
// set by cp_va_parse:
const cp_argtype* argtype;
const char* keyword;
const char* description CLICK_CONFPARSE_DEPRECATED;
union {
int i;
const char *c_str;
void *p;
} extra;
void* store;
void* store2;
bool* store_confirm;
// set by parsefunc, used by storefunc:
union {
bool b;
int i;
unsigned u;
int16_t s16;
uint16_t u16;
int32_t s32;
uint32_t u32;
#if HAVE_INT64_TYPES
int64_t s64;
int64_t i64 CLICK_DEPRECATED;
uint64_t u64;
#endif
size_t size;
#if HAVE_FLOAT_TYPES
double d;
#endif
unsigned char address[16];
int is[4];
#ifndef CLICK_TOOL
Element *element;
#endif
void *p;
} v, v2;
String v_string;
String v2_string;
};
enum {
cpArgNormal = 0, cpArgStore2 = 1, cpArgExtraInt = 2,
cpArgExtraCStr = 4, cpArgAllowNumbers = 8
};
int cp_register_argtype(const char* name, const char* description, int flags,
cp_parsefunc parsefunc, cp_storefunc storefunc,
void* user_data = 0);
void cp_unregister_argtype(const char* name);
int cp_register_stringlist_argtype(const char* name, const char* description,
int flags);
int cp_extend_stringlist_argtype(const char* name, ...);
// Takes: const char* name, int value, ...., const char* ender = (const char*)0
//@}
/// @cond never
bool cp_seconds_as(int want_power, const String& str, uint32_t* result) CLICK_DEPRECATED;
#define cp_integer64 cp_integer
#define cp_unsigned64 cp_integer
#define cp_unsigned cp_integer
#define cp_unsigned_real10 cp_real10
#define cp_unsigned_real2 cp_real2
/// @endcond
/** @brief Join the strings in @a conf with spaces and return the result.
*
* This function does not quote or otherwise protect the strings in @a conf.
* The caller should do that if necessary.
* @sa cp_unspacevec(const String *, const String *) */
inline String cp_unspacevec(const Vector<String>& conf)
{
return cp_unspacevec(conf.begin(), conf.end());
}
/** @brief Test if @a str is all spaces.
* @return True when every character in @a str is a space. */
inline bool cp_is_space(const String& str)
{
return cp_skip_space(str.begin(), str.end()) == str.end();
}
/** @brief Parse an integer from [@a begin, @a end) in base @a base.
* @param begin first character in string
* @param end one past last character in string
* @param base base of integer: 0 or 2-36
* @param[out] result stores parsed result
* @return pointer to first unparsed character in string; equals @a begin
* if the string didn't start with a valid integer
*
* This function parses an integer from the initial characters of a string.
* The resulting integer is stored in *@a result.
*
* The integer format consists of an optional initial sign <tt>+/-</tt>,
* followed by one or more digits. A negative sign is only accepted if @a
* result has a signed type. Digits may be separated by underscores (to make
* numbers easier to read), but the first and last characters in the integer
* cannot be underscores, and two underscores can't appear in a row. Some
* examples:
*
* @code
* 0
* 0x100
* -1_000_023
* @endcode
*
* Digits are numbered from 0-9, then A-Z/a-z. @a base determines which
* digits are legal. If @a base is 0, then a leading <tt>0x</tt> or
* <tt>0X</tt> may precede the digits, indicating base 16; a leading
* <tt>0</tt> indicates base 8; anything else is base 10.
*
* Returns the first character that can't be parsed as part of the integer.
* If there is no valid integer at the beginning of the string, then returns
* @a begin; *@a result is unchanged.
*
* This function checks for overflow. If an integer is too large for @a
* result, then the maximum possible value is stored in @a result and the
* cp_errno variable is set to CPE_OVERFLOW. Otherwise, cp_errno is set to
* CPE_FORMAT (for no valid integer) or CPE_OK (if all was well).
*
* Overloaded versions of this function are available for int, unsigned int,
* long, unsigned long, and (depending on configuration) long long and
* unsigned long long @a result values.
*/
inline const char *cp_integer(const char *begin, const char *end, int base, int *result)
{
return cp_basic_integer(begin, end, base, -(int) sizeof(*result), result);
}
/** @brief Parse an integer from @a str in base @a base.
* @param str string
* @param base base of integer: 0 or 2-36
* @param[out] result stores parsed result
* @return True if @a str parsed correctly, false otherwise.
*
* Parses an integer from an input string. If the string correctly parses as
* an integer, then the resulting value is stored in *@a result and the
* function returns true. Otherwise, *@a result remains unchanged and the
* function returns false.
*
* Overloaded versions are available for int, unsigned int, long, unsigned
* long, and (depending on configuration) long long and unsigned long long @a
* result values.
*
* @sa cp_integer(const char *, const char *, int, int *) for the rules on
* parsing integers.
*/
inline bool cp_integer(const String &str, int base, int *result)
{
return cp_basic_integer(str.begin(), str.end(), base + cp_basic_integer_whole, -(int) sizeof(*result), result) != str.begin();
}
inline const char *cp_integer(const char *begin, const char *end, int base, unsigned *result)
{
return cp_basic_integer(begin, end, base, (int) sizeof(*result), result);
}
/// @cond never
inline const unsigned char *cp_integer(const unsigned char *begin, const unsigned char *end, int base, unsigned *result)
{
return reinterpret_cast<const unsigned char *>(cp_integer(reinterpret_cast<const char *>(begin), reinterpret_cast<const char *>(end), base, result));
}
/// @endcond
inline const char *cp_integer(const char *begin, const char *end, int base, long *result)
{
return cp_basic_integer(begin, end, base, -(int) sizeof(*result), result);
}
inline const char *cp_integer(const char *begin, const char *end, int base, unsigned long *result)
{
return cp_basic_integer(begin, end, base, (int) sizeof(*result), result);
}
/// @cond never
inline const unsigned char *cp_integer(const unsigned char *begin, const unsigned char *end, int base, unsigned long *result)
{
return reinterpret_cast<const unsigned char *>(cp_integer(reinterpret_cast<const char *>(begin), reinterpret_cast<const char *>(end), base, result));
}
/// @endcond
#if HAVE_LONG_LONG
inline const char *cp_integer(const char *begin, const char *end, int base, long long *result)
{
return cp_basic_integer(begin, end, base, -(int) sizeof(*result), result);
}
inline const char *cp_integer(const char *begin, const char *end, int base, unsigned long long *result)
{
return cp_basic_integer(begin, end, base, (int) sizeof(*result), result);
}
/// @cond never
inline const unsigned char *cp_integer(const unsigned char *begin, const unsigned char *end, int base, unsigned long long *result)
{
return reinterpret_cast<const unsigned char *>(cp_integer(reinterpret_cast<const char *>(begin), reinterpret_cast<const char *>(end), base, result));
}
/// @endcond
#elif HAVE_INT64_TYPES && !HAVE_INT64_IS_LONG
inline const char *cp_integer(const char *begin, const char *end, int base, int64_t *result)
{
return cp_basic_integer(begin, end, base, -(int) sizeof(*result), result);
}
inline const char *cp_integer(const char *begin, const char *end, int base, uint64_t *result)
{
return cp_basic_integer(begin, end, base, (int) sizeof(*result), result);
}
/// @cond never
inline const unsigned char *cp_integer(const unsigned char *begin, const unsigned char *end, int base, uint64_t *result)
{
return reinterpret_cast<const unsigned char *>(cp_integer(reinterpret_cast<const char *>(begin), reinterpret_cast<const char *>(end), base, result));
}
/// @endcond
#endif
inline bool cp_integer(const String &str, int base, int *result);
inline bool cp_integer(const String &str, int base, unsigned int *result)
{
return cp_basic_integer(str.begin(), str.end(), base + cp_basic_integer_whole, (int) sizeof(*result), result) != str.begin();
}
inline bool cp_integer(const String &str, int base, long *result)
{
return cp_basic_integer(str.begin(), str.end(), base + cp_basic_integer_whole, -(int) sizeof(*result), result) != str.begin();
}
inline bool cp_integer(const String &str, int base, unsigned long *result)
{
return cp_basic_integer(str.begin(), str.end(), base + cp_basic_integer_whole, (int) sizeof(*result), result) != str.begin();
}
#if HAVE_LONG_LONG
inline bool cp_integer(const String &str, int base, long long *result)
{
return cp_basic_integer(str.begin(), str.end(), base + cp_basic_integer_whole, -(int) sizeof(*result), result) != str.begin();
}
inline bool cp_integer(const String &str, int base, unsigned long long *result)
{
return cp_basic_integer(str.begin(), str.end(), base + cp_basic_integer_whole, (int) sizeof(*result), result) != str.begin();
}
#elif HAVE_INT64_TYPES && !HAVE_INT64_IS_LONG
inline bool cp_integer(const String &str, int base, int64_t *result)
{
return cp_basic_integer(str.begin(), str.end(), base + cp_basic_integer_whole, -(int) sizeof(*result), result) != str.begin();
}
inline bool cp_integer(const String &str, int base, uint64_t *result)
{
return cp_basic_integer(str.begin(), str.end(), base + cp_basic_integer_whole, (int) sizeof(*result), result) != str.begin();
}
#endif
/** @brief Parse an integer from @a str in base 0.
*
* Same as cp_integer(str, 0, result). */
inline bool cp_integer(const String &str, int *result)
{
return cp_basic_integer(str.begin(), str.end(), cp_basic_integer_whole, -(int) sizeof(*result), result) != str.begin();
}
inline bool cp_integer(const String &str, unsigned int *result)
{
return cp_basic_integer(str.begin(), str.end(), cp_basic_integer_whole, (int) sizeof(*result), result) != str.begin();
}
inline bool cp_integer(const String &str, long *result)
{
return cp_basic_integer(str.begin(), str.end(), cp_basic_integer_whole, -(int) sizeof(*result), result) != str.begin();
}
inline bool cp_integer(const String &str, unsigned long *result)
{
return cp_basic_integer(str.begin(), str.end(), cp_basic_integer_whole, (int) sizeof(*result), result) != str.begin();
}
#if HAVE_LONG_LONG
inline bool cp_integer(const String &str, long long *result)
{
return cp_basic_integer(str.begin(), str.end(), cp_basic_integer_whole, -(int) sizeof(*result), result) != str.begin();
}
inline bool cp_integer(const String &str, unsigned long long *result)
{
return cp_basic_integer(str.begin(), str.end(), cp_basic_integer_whole, (int) sizeof(*result), result) != str.begin();
}
#elif HAVE_INT64_TYPES && !HAVE_INT64_IS_LONG
inline bool cp_integer(const String &str, int64_t *result)
{
return cp_basic_integer(str.begin(), str.end(), cp_basic_integer_whole, -(int) sizeof(*result), result) != str.begin();
}
inline bool cp_integer(const String &str, uint64_t *result)
{
return cp_basic_integer(str.begin(), str.end(), cp_basic_integer_whole, (int) sizeof(*result), result) != str.begin();
}
#endif
inline bool cp_ip_address(const String& str, struct in_addr *ina CP_CONTEXT)
{
return cp_ip_address(str, reinterpret_cast<IPAddress *>(ina) CP_PASS_CONTEXT);
}
#if HAVE_IP6
inline bool cp_ip6_address(const String& str, struct in6_addr *x CP_CONTEXT)
{
return cp_ip6_address(str, reinterpret_cast<IP6Address *>(x) CP_PASS_CONTEXT);
}
#endif
/// @cond never
inline bool cp_seconds_as(int want_power, const String &str, uint32_t *result)
{
return cp_seconds_as(str, want_power, result);
}
#if !CLICK_TOOL
inline int cp_register_argtype(const char* name, const char* description, int flags,
void (*parsefunc)(cp_value *, const String &, ErrorHandler *, const char *, Element *),
void (*storefunc)(cp_value *, Element *),
void *user_data = 0) {
return cp_register_argtype(name, description, flags,
(cp_parsefunc) parsefunc,
(cp_storefunc) storefunc,
user_data);
}
#endif
inline String cp_pop_spacevec(String &str) CLICK_DEPRECATED;
/// @brief Remove and return the first space-separated argument from @a str.
/// @param[in,out] str space-separated configuration string
/// @deprecated This is a deprecated synonym for cp_shift_spacevec().
inline String cp_pop_spacevec(String &str) {
return cp_shift_spacevec(str);
}
#undef CP_VA_ARGS_REST
#undef CP_OPT_CONTEXT
#undef CP_CONTEXT
#undef CP_PASS_CONTEXT
#undef CLICK_CONFPARSE_DEPRECATED
#undef CP_SENTINEL
#define cpEnd ((CpVaParseCmd) 0)
/// @endcond
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,14 @@
/* -*- related-file-name: "../../lib/crc32.c" -*- */
#ifndef CLICK_CRC32_H
#define CLICK_CRC32_H
#ifdef __cplusplus
extern "C" {
#endif
uint32_t update_crc(uint32_t crc_accum, const char *data_blk_ptr,
int data_blk_size);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,25 @@
#ifdef __cplusplus
# define new linux_new
# define this linux_this
# define delete linux_delete
# define class linux_class
# define virtual linux_virtual
# define typename linux_typename
# define protected linux_protected
# define public linux_public
# define namespace linux_namespace
# define false linux_false
# define true linux_true
#endif
#ifndef CLICK_CXX_PROTECT
# ifdef __cplusplus
# define CLICK_CXX_PROTECT extern "C" {
# define CLICK_CXX_UNPROTECT }
# else
# define CLICK_CXX_PROTECT /* nothing */
# define CLICK_CXX_UNPROTECT /* nothing */
# endif
#endif
#define CLICK_CXX_PROTECTED 1

View File

@ -0,0 +1,14 @@
#ifdef __cplusplus
# undef new
# undef this
# undef delete
# undef class
# undef virtual
# undef typename
# undef protected
# undef public
# undef namespace
# undef false
# undef true
#endif
#undef CLICK_CXX_PROTECTED

View File

@ -0,0 +1,211 @@
/*
* deque.{cc,hh} -- double-ended queue template class
* Eddie Kohler, Douglas S. J. De Couto
* Based on code from Click Vector<> class (vector.{cc,hh}).
*
* Copyright (c) 2003 Massachusetts Institute of Technology
* Copyright (c) 2011 Eddie Kohler
*
* 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.
*/
#ifndef CLICK_DEQUE_CC
#define CLICK_DEQUE_CC
#include <click/deque.hh>
CLICK_DECLS
/** @cond never */
template <typename AM>
deque_memory<AM>::~deque_memory()
{
size_type f = naccess(n_);
AM::destroy(l_ + head_, f);
AM::destroy(l_, n_ - f);
CLICK_LFREE(l_, capacity_ * sizeof(type));
}
template <typename AM>
void deque_memory<AM>::assign(const deque_memory<AM> &x)
{
if (&x != this) {
size_type f = naccess(n_);
AM::destroy(l_ + head_, f);
AM::destroy(l_, n_ - f);
n_ = head_ = 0;
if (reserve_and_push(x.n_, false, 0)) {
n_ = x.n_;
AM::mark_undefined(l_, n_);
f = x.naccess(n_);
AM::copy(l_, x.l_ + x.head_, f);
AM::copy(l_ + f, x.l_, n_ - f);
}
}
}
template <typename AM>
void deque_memory<AM>::assign(size_type n, const type *vp)
{
if (unlikely(need_argument_copy(vp))) {
type v_copy(*vp);
return assign(n, &v_copy);
}
resize(0, vp);
resize(n, vp);
}
template <typename AM>
bool deque_memory<AM>::insert(size_type i, const type *vp)
{
assert((unsigned) i <= (unsigned) n_);
if (unlikely(need_argument_copy(vp))) {
type v_copy(*vp);
return insert(i, &v_copy);
}
if (n_ == capacity_ && !reserve_and_push(-1, false, 0))
return false;
size_type srcpp, dstpp, size;
int delta;
if (i <= n_ - i) {
head_ = prevp(head_);
srcpp = head_ + 1;
dstpp = head_;
size = i;
delta = 1;
} else {
srcpp = head_ + n_ - 1;
dstpp = head_ + n_;
size = n_ - i;
delta = -1;
}
while (size) {
AM::mark_undefined(l_ + canonp(dstpp), 1);
AM::move(l_ + canonp(dstpp), l_ + canonp(srcpp), 1);
dstpp += delta, srcpp += delta, --size;
}
AM::mark_undefined(l_ + canonp(dstpp), 1);
AM::fill(l_ + canonp(dstpp), 1, vp);
++n_;
return true;
}
template <typename AM>
int deque_memory<AM>::erase(size_type ai, size_type bi)
{
assert(ai >= bi || (ai >= 0 && (unsigned) bi <= (unsigned) n_));
if (ai < bi) {
size_type srcpp, dstpp, size;
int delta;
if (ai < n_ - bi) {
srcpp = head_ + ai - 1;
dstpp = head_ + bi - 1;
size = ai;
delta = -1;
head_ = canonp(head_ + bi - ai);
} else {
srcpp = head_ + bi;
dstpp = head_ + ai;
size = n_ - bi;
delta = 1;
}
while (size) {
AM::destroy(l_ + canonp(dstpp), 1);
AM::copy(l_ + canonp(dstpp), l_ + canonp(srcpp), 1);
dstpp += delta, srcpp += delta, --size;
}
for (size = bi - ai; size; --size, dstpp += delta) {
AM::destroy(l_ + canonp(dstpp), 1);
AM::mark_noaccess(l_ + canonp(dstpp), 1);
}
n_ -= bi - ai;
return ai;
} else
return bi;
}
template <typename AM>
bool deque_memory<AM>::reserve_and_push(size_type want, bool isfront, const type *push_vp)
{
if (unlikely(push_vp && need_argument_copy(push_vp))) {
type push_v_copy(*push_vp);
return reserve_and_push(want, isfront, &push_v_copy);
}
if (want < 0)
want = (capacity_ > 0 ? capacity_ * 2 : 4);
if (want > capacity_) {
type *new_l = (type *) CLICK_LALLOC(want * sizeof(type));
if (!new_l)
return false;
AM::mark_noaccess(new_l + n_, want - n_);
size_type f = naccess(n_);
AM::move(new_l, l_ + head_, f);
AM::move(new_l + f, l_, n_ - f);
CLICK_LFREE(l_, capacity_ * sizeof(type));
l_ = new_l;
head_ = 0;
capacity_ = want;
}
if (unlikely(push_vp))
(isfront ? push_front(push_vp) : push_back(push_vp));
return true;
}
template <typename AM>
void deque_memory<AM>::resize(size_type n, const type *vp)
{
if (unlikely(need_argument_copy(vp))) {
type v_copy(*vp);
return resize(n, &v_copy);
}
if (n <= capacity_ || reserve_and_push(n, false, 0)) {
assert(n >= 0);
if (n < n_)
for (size_type p = i2p(n), x = i2p(n_); p != x; p = nextp(p)) {
AM::destroy(l_ + p, 1);
AM::mark_noaccess(l_ + p, 1);
}
if (n_ < n)
for (size_type p = i2p(n_), x = i2p(n); p != x; p = nextp(p)) {
AM::mark_undefined(l_ + p, 1);
AM::fill(l_ + p, 1, vp);
}
n_ = n;
}
}
template <typename AM>
void deque_memory<AM>::swap(deque_memory<AM> &x)
{
type *l = l_;
l_ = x.l_;
x.l_ = l;
size_type head = head_;
head_ = x.head_;
x.head_ = head;
size_type n = n_;
n_ = x.n_;
x.n_ = n;
size_type capacity = capacity_;
capacity_ = x.capacity_;
x.capacity_ = capacity;
}
/** @endcond never */
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,687 @@
#ifndef CLICK_DEQUE_HH
#define CLICK_DEQUE_HH 1
#include <click/algorithm.hh>
#include <click/array_memory.hh>
CLICK_DECLS
/** @cond never */
template <typename AM> class deque_memory { public:
typedef int size_type;
typedef typename AM::type type;
inline bool need_argument_copy(const type *argp) const {
return fast_argument<type>::is_reference && (uintptr_t) argp - (uintptr_t) l_ < (size_t) (capacity_ * sizeof(type));
}
inline size_type canonp(size_type p) const {
return p < capacity_ ? p : p - capacity_;
}
inline size_type i2p(size_type i) const {
return canonp(head_ + i);
}
inline size_type prevp(size_type p) const {
return p ? p - 1 : capacity_ - 1;
}
inline size_type nextp(size_type p) const {
return p + 1 != capacity_ ? p + 1 : 0;
}
inline size_type naccess(size_type n) const {
return head_ + n <= capacity_ ? n : capacity_ - head_;
}
deque_memory()
: l_(0), head_(0), n_(0), capacity_(0) {
}
~deque_memory();
void assign(const deque_memory<AM> &x);
void assign(size_type n, const type *vp);
void resize(size_type n, const type *vp);
bool insert(int i, const type *vp);
int erase(int ai, int bi);
inline void push_back(const type *vp) {
if (n_ < capacity_) {
size_type p = i2p(n_);
AM::mark_undefined(l_ + p, 1);
AM::fill(l_ + p, 1, vp);
++n_;
} else
reserve_and_push(-1, false, vp);
}
#if HAVE_CXX_RVALUE_REFERENCES
inline void move_construct_back(type* vp) {
if (n_ < capacity_) {
size_type p = i2p(n_);
AM::mark_undefined(l_ + p, 1);
AM::move_construct(l_ + p, vp);
++n_;
} else
reserve_and_push(-1, false, vp);
}
#endif
inline void pop_back() {
assert(n_ > 0);
--n_;
size_type p = i2p(n_);
AM::destroy(l_ + p, 1);
AM::mark_noaccess(l_ + p, 1);
}
inline void push_front(const type *vp) {
if (n_ < capacity_) {
head_ = prevp(head_);
AM::mark_undefined(l_ + head_, 1);
AM::fill(l_ + head_, 1, vp);
++n_;
} else
reserve_and_push(-1, true, vp);
}
#if HAVE_CXX_RVALUE_REFERENCES
inline void move_construct_front(type* vp) {
if (n_ < capacity_) {
head_ = prevp(head_);
AM::mark_undefined(l_ + head_, 1);
AM::move_construct(l_ + head_, vp);
++n_;
} else
reserve_and_push(-1, true, vp);
}
#endif
inline void pop_front() {
assert(n_ > 0);
--n_;
AM::destroy(l_ + head_, 1);
AM::mark_noaccess(l_ + head_, 1);
head_ = nextp(head_);
}
inline void clear() {
size_type f = naccess(n_);
AM::destroy(l_ + head_, f);
AM::destroy(l_, n_ - f);
AM::mark_noaccess(l_, capacity_);
head_ = n_ = 0;
}
bool reserve_and_push(size_type n, bool isfront, const type *vp);
void swap(deque_memory<AM> &x);
type *l_;
size_type head_;
size_type n_;
size_type capacity_;
};
/** @endcond never */
template <typename T> class Deque_iterator;
template <typename T> class Deque_const_iterator;
/** @class Deque
@brief Deque template.
Deque implements a double-ended queue: a growable array that can efficiently
add and remove elements at both ends (see push_back(), pop_back(),
push_front(), and pop_front()). Its interface should be compatible with
C++'s std::deque, although that type has more methods. Deque elements are
accessed with operator[] like arrays.
Deque is implemented using a circular buffer of elements. This makes its
operations slightly slower than those of Vector. If you only need to push
elements to the end of an array, prefer Vector.
Example code:
@code
Deque<int> d;
printf("%d\n", d.size()); // prints "0"
d.push_back(1);
d.push_back(2);
printf("%d\n", d.size()); // prints "2"
printf("%d %d\n", d[0], d[1]); // prints "1 2"
d.push_front(0);
d.push_front(-1);
printf("%d\n", d.size()); // prints "4"
printf("%d %d %d %d\n", d[0], d[1], d[2], d[3]);
// prints "-1 0 1 2"
d.pop_front();
d.pop_back();
printf("%d\n", d.size()); // prints "2"
printf("%d %d\n", d[0], d[1]); // prints "0 1"
@endcode
*/
template <typename T>
class Deque {
typedef typename array_memory<T>::type array_memory_type;
mutable deque_memory<array_memory_type> vm_;
public:
typedef T value_type; ///< Value type.
typedef T &reference; ///< Reference to value type.
typedef const T &const_reference; ///< Const reference to value type.
typedef T *pointer; ///< Pointer to value type.
typedef const T *const_pointer; ///< Pointer to const value type.
/** @brief Type used for value arguments (either T or const T &). */
typedef typename fast_argument<T>::type value_argument_type;
typedef const T &const_access_type;
typedef int size_type; ///< Type of sizes (size()).
typedef Deque_iterator<T> iterator; ///< Iterator type.
typedef Deque_const_iterator<T> const_iterator; ///< Const iterator type.
/** @brief Constant passed to reserve() to grow the deque. */
enum { RESERVE_GROW = (size_type) -1 };
explicit inline Deque();
explicit inline Deque(size_type n, value_argument_type v);
inline Deque(const Deque<T> &x);
#if HAVE_CXX_RVALUE_REFERENCES
inline Deque(Deque<T> &&x);
#endif
inline Deque<T> &operator=(const Deque<T> &x);
#if HAVE_CXX_RVALUE_REFERENCES
inline Deque<T> &operator=(Deque<T> &&x);
#endif
inline Deque<T> &assign(size_type n, value_argument_type v = T());
inline iterator begin();
inline iterator end();
inline const_iterator begin() const;
inline const_iterator end() const;
inline const_iterator cbegin() const;
inline const_iterator cend() const;
inline size_type size() const;
inline size_type capacity() const;
inline bool empty() const;
inline void resize(size_type n, value_argument_type v = T());
inline bool reserve(size_type n);
inline T &operator[](size_type i);
inline const T &operator[](size_type i) const;
inline T &at(size_type i);
inline const T &at(size_type i) const;
inline T &front();
inline const T &front() const;
inline T &back();
inline const T &back() const;
inline T &unchecked_at(size_type i);
inline const T &unchecked_at(size_type i) const;
inline T &at_u(size_type i) CLICK_DEPRECATED;
inline const T &at_u(size_type i) const CLICK_DEPRECATED;
inline void push_back(value_argument_type v);
#if HAVE_CXX_RVALUE_REFERENCES
template <typename A = fast_argument<T> >
inline typename A::enable_rvalue_reference push_back(T &&v);
#endif
inline void pop_back();
inline void push_front(value_argument_type v);
#if HAVE_CXX_RVALUE_REFERENCES
template <typename A = fast_argument<T> >
inline typename A::enable_rvalue_reference push_front(T &&v);
#endif
inline void pop_front();
inline iterator insert(iterator it, value_argument_type v);
inline iterator erase(iterator it);
inline iterator erase(iterator a, iterator b);
inline void clear();
inline void swap(Deque<T> &x);
};
template <typename T>
class Deque_const_iterator {
const Deque<T> *q_;
typename Deque<T>::size_type p_;
friend class Deque<T>;
public:
typedef typename Deque<T>::size_type size_type;
typedef Deque_const_iterator<T> const_iterator;
typedef Deque_iterator<T> iterator;
Deque_const_iterator() {
}
Deque_const_iterator(const Deque<T> *q, size_type p)
: q_(q), p_(p) {
}
const T *operator->() const {
return &(*q_)[p_];
}
const T &operator*() const {
return (*q_)[p_];
}
const T &operator[](size_type i) const {
return (*q_)[p_ + i];
}
bool operator==(const const_iterator &x) const {
return p_ == x.p_ && q_ == x.q_;
}
bool operator!=(const const_iterator &x) const {
return p_ != x.p_ || q_ != x.q_;
}
bool operator<(const const_iterator &x) const {
assert(q_ == x.q_);
return p_ < x.p_;
}
bool operator<=(const const_iterator &x) const {
assert(q_ == x.q_);
return p_ <= x.p_;
}
bool operator>=(const const_iterator &x) const {
assert(q_ == x.q_);
return p_ >= x.p_;
}
bool operator>(const const_iterator &x) const {
assert(q_ == x.q_);
return p_ > x.p_;
}
size_type diff(const const_iterator &x) const {
assert(q_ == x.q_);
return p_ - x.p_;
}
void operator++(int) {
++p_;
}
const_iterator &operator++() {
++p_;
return *this;
}
void operator--(int) {
--p_;
}
const_iterator &operator--() {
--p_;
return *this;
}
const_iterator &operator+=(size_type n) {
p_ += n;
return *this;
}
const_iterator &operator-=(size_type n) {
p_ -= n;
return *this;
}
};
template <typename T>
class Deque_iterator : public Deque_const_iterator<T> { public:
typedef typename Deque<T>::size_type size_type;
typedef Deque_const_iterator<T> const_iterator;
typedef Deque_iterator<T> iterator;
Deque_iterator() {
}
Deque_iterator(Deque<T> *q, int p)
: const_iterator(q, p) {
}
T *operator->() const {
return const_cast<T *>(const_iterator::operator->());
}
T &operator*() const {
return const_cast<T &>(const_iterator::operator*());
}
T &operator[](int n) const {
return const_cast<T &>(const_iterator::operator[](n));
}
iterator &operator+=(size_type n) {
const_iterator::operator+=(n);
return *this;
}
iterator &operator-=(size_type n) {
const_iterator::operator-=(n);
return *this;
}
};
/** @brief Construct an empty deque. */
template <typename T>
inline Deque<T>::Deque() {
}
/** @brief Construct a deque containing @a n copies of @a v. */
template <typename T>
inline Deque<T>::Deque(size_type n, value_argument_type v) {
vm_.resize(n, array_memory_type::cast(&v));
}
/** @brief Construct a deque as a copy of @a x. */
template <typename T>
inline Deque<T>::Deque(const Deque<T> &x) {
vm_.assign(x.vm_);
}
#if HAVE_CXX_RVALUE_REFERENCES
/** @brief Construct a deque as a copy of @a x. */
template <typename T>
inline Deque<T>::Deque(Deque<T> &&x) {
vm_.assign(x.vm_);
}
#endif
/** @brief Return the number of elements. */
template <typename T>
inline typename Deque<T>::size_type Deque<T>::size() const {
return vm_.n_;
}
/** @brief Test if the deque is empty (size() == 0). */
template <typename T>
inline bool Deque<T>::empty() const {
return vm_.n_ == 0;
}
/** @brief Return the deque's capacity.
The capacity is greater than or equal to the size(). Functions such as
resize(n) will not allocate new memory for the deque if n <=
capacity(). */
template <typename T>
inline typename Deque<T>::size_type Deque<T>::capacity() const {
return vm_.capacity_;
}
/** @brief Return an iterator for the first element in the deque. */
template <typename T>
inline typename Deque<T>::iterator Deque<T>::begin() {
return iterator(this, 0);
}
/** @overload */
template <typename T>
inline typename Deque<T>::const_iterator Deque<T>::begin() const {
return const_iterator(this, 0);
}
/** @brief Return an iterator for the end of the deque.
@invariant end() == begin() + size() */
template <typename T>
inline typename Deque<T>::iterator Deque<T>::end() {
return iterator(this, vm_.n_);
}
/** @overload */
template <typename T>
inline typename Deque<T>::const_iterator Deque<T>::end() const {
return const_iterator(this, vm_.n_);
}
/** @brief Return a const_iterator for the beginning of the deque. */
template <typename T>
inline typename Deque<T>::const_iterator Deque<T>::cbegin() const {
return const_iterator(this, 0);
}
/** @brief Return a const_iterator for the end of the deque.
@invariant end() == begin() + size() */
template <typename T>
inline typename Deque<T>::const_iterator Deque<T>::cend() const {
return const_iterator(this, vm_.n_);
}
/** @brief Return a reference to the <em>i</em>th element.
@pre 0 <= @a i < size() */
template <typename T>
inline T &Deque<T>::operator[](size_type i) {
assert((unsigned) i < (unsigned) vm_.n_);
return *(T *)&vm_.l_[vm_.i2p(i)];
}
/** @overload */
template <typename T>
inline const T &Deque<T>::operator[](size_type i) const {
assert((unsigned) i < (unsigned) vm_.n_);
return *(T *)&vm_.l_[vm_.i2p(i)];
}
/** @brief Return a reference to the <em>i</em>th element.
@pre 0 <= @a i < size()
@sa operator[]() */
template <typename T>
inline T &Deque<T>::at(size_type i) {
return operator[](i);
}
/** @overload */
template <typename T>
inline const T &Deque<T>::at(size_type i) const {
return operator[](i);
}
/** @brief Return a reference to the first element.
@pre !empty() */
template <typename T>
inline T &Deque<T>::front() {
return operator[](0);
}
/** @overload */
template <typename T>
inline const T &Deque<T>::front() const {
return operator[](0);
}
/** @brief Return a reference to the last element (number size()-1).
@pre !empty() */
template <typename T>
inline T &Deque<T>::back() {
return operator[](vm_.n_ - 1);
}
/** @overload */
template <typename T>
inline const T &Deque<T>::back() const {
return operator[](vm_.n_ - 1);
}
/** @brief Return a reference to the <em>i</em>th element.
@pre 0 <= @a i < size()
Unlike operator[]() and at(), this function does not check bounds,
even if assertions are enabled. Use with caution. */
template <typename T>
inline T &Deque<T>::unchecked_at(size_type i) {
return *(T *)&vm_.l_[vm_.i2p(i)];
}
/** @overload */
template <typename T>
inline const T &Deque<T>::unchecked_at(size_type i) const {
return *(T *)&vm_.l_[vm_.i2p(i)];
}
/** @cond never */
template <typename T>
inline T &Deque<T>::at_u(size_type i) {
return unchecked_at(i);
}
template <typename T>
inline const T &Deque<T>::at_u(size_type i) const {
return unchecked_at(i);
}
/** @endcond never */
/** @brief Resize the deque to contain @a n elements.
@param n new size
@param v value used to fill new elements */
template <typename T>
inline void Deque<T>::resize(size_type n, value_argument_type v) {
vm_.resize(n, array_memory_type::cast(&v));
}
/** @brief Append @a v to the end of the deque.
A copy of @a v is added to position size(). Takes amortized O(1)
time. */
template <typename T>
inline void Deque<T>::push_back(value_argument_type v) {
vm_.push_back(array_memory_type::cast(&v));
}
#if HAVE_CXX_RVALUE_REFERENCES
/** @overload */
template <typename T> template <typename A>
inline typename A::enable_rvalue_reference Deque<T>::push_back(T&& v) {
vm_.move_construct_back(array_memory_type::cast(&v));
}
#endif
/** @brief Remove the last element.
Takes O(1) time. */
template <typename T>
inline void Deque<T>::pop_back() {
vm_.pop_back();
}
/** @brief Prepend element @a v.
A copy of @a v is added to position 0. Other elements are shifted one
position forward. Takes amortized O(1) time. */
template <typename T>
inline void Deque<T>::push_front(value_argument_type v) {
vm_.push_front(array_memory_type::cast(&v));
}
#if HAVE_CXX_RVALUE_REFERENCES
/** @overload */
template <typename T> template <typename A>
inline typename A::enable_rvalue_reference Deque<T>::push_front(T&& v) {
vm_.move_construct_front(array_memory_type::cast(&v));
}
#endif
/** @brief Remove the first element.
Other elements are shifted one position backward. Takes O(1) time. */
template <typename T>
inline void Deque<T>::pop_front() {
vm_.pop_front();
}
/** @brief Insert @a v before position @a it.
@return An iterator pointing at the new element. */
template <typename T>
inline typename Deque<T>::iterator
Deque<T>::insert(iterator it, value_argument_type v) {
assert(it.q_ == this);
if (likely(vm_.insert(it.p_, array_memory_type::cast(&v))))
return it;
else
return end();
}
/** @brief Remove the element at position @a it.
@return An iterator pointing at the element following @a it. */
template <typename T>
inline typename Deque<T>::iterator
Deque<T>::erase(iterator it) {
assert(it.q_ == this);
return (it < end() ? erase(it, it + 1) : it);
}
/** @brief Remove the elements in [@a a, @a b).
@return An iterator corresponding to @a b. */
template <typename T>
inline typename Deque<T>::iterator
Deque<T>::erase(iterator a, iterator b) {
assert(a.q_ == this && b.q_ == this);
return iterator(this, vm_.erase(a.p_, b.p_));
}
/** @brief Remove all elements.
@post size() == 0 */
template <typename T>
inline void Deque<T>::clear() {
vm_.clear();
}
/** @brief Reserve space for at least @a n more elements.
@return true iff reserve succeeded.
This function changes the deque's capacity(), not its size(). If
reserve(@a n) succeeds, then any succeeding call to resize(@a m) with @a
m < @a n will succeed without allocating deque memory. */
template <typename T>
inline bool Deque<T>::reserve(size_type n) {
return vm_.reserve_and_push(n, false, 0);
}
/** @brief Swap the contents of this deque and @a x. */
template <typename T>
inline void Deque<T>::swap(Deque<T> &x) {
vm_.swap(x.vm_);
}
/** @brief Replace this deque's contents with a copy of @a x. */
template <typename T>
inline Deque<T> &Deque<T>::operator=(const Deque<T> &x) {
vm_.assign(x.vm_);
return *this;
}
#if HAVE_CXX_RVALUE_REFERENCES
/** @brief Replace this deque's contents with those of @a x. */
template <typename T>
inline Deque<T> &Deque<T>::operator=(Deque<T> &&x) {
vm_.swap(x.vm_);
return *this;
}
#endif
/** @brief Replace this deque's contents with @a n copies of @a v.
@post size() == @a n */
template <typename T>
inline Deque<T> &Deque<T>::assign(size_type n, value_argument_type v) {
vm_.assign(n, array_memory_type::cast(&v));
return *this;
}
template <typename T>
Deque_const_iterator<T> operator+(Deque_const_iterator<T> it,
typename Deque<T>::size_type n) {
return it += n;
}
template <typename T>
Deque_const_iterator<T> operator-(Deque_const_iterator<T> it,
typename Deque<T>::size_type n) {
return it -= n;
}
template <typename T>
Deque_iterator<T> operator+(Deque_iterator<T> it,
typename Deque<T>::size_type n) {
return it += n;
}
template <typename T>
Deque_iterator<T> operator-(Deque_iterator<T> it,
typename Deque<T>::size_type n) {
return it -= n;
}
template <typename T>
typename Deque_const_iterator<T>::size_type
operator-(const Deque_const_iterator<T> &a, const Deque_const_iterator<T> &b) {
return a.diff(b);
}
template <typename T>
inline void click_swap(Deque<T> &a, Deque<T> &b) {
a.swap(b);
}
template <typename T>
inline void assign_consume(Deque<T> &a, Deque<T> &b) {
a.swap(b);
}
CLICK_ENDDECLS
#include <click/deque.cc>
#endif

View File

@ -0,0 +1,5 @@
#ifndef DEQueue
#warning "DEQueue is deprecated, use Deque and <click/deque.hh> instead"
#include <click/deque.hh>
#define DEQueue Deque
#endif

View File

@ -0,0 +1,210 @@
#ifndef CLICK_DPDKDEVICE_HH
#define CLICK_DPDKDEVICE_HH
/**
* Prevent bug under some configurations
* (like travis-ci's one) where these
* macros get undefined.
*/
#ifndef UINT8_MAX
#define UINT8_MAX 255
#endif
#ifndef UINT16_MAX
#define UINT16_MAX 65535
#endif
#include <rte_common.h>
#include <rte_eal.h>
#include <rte_ethdev.h>
#include <rte_lcore.h>
#include <rte_mbuf.h>
#include <rte_mempool.h>
#include <rte_pci.h>
#include <rte_version.h>
#include <click/packet.hh>
#include <click/error.hh>
#include <click/hashtable.hh>
#include <click/vector.hh>
#include <click/args.hh>
#include <click/etheraddress.hh>
#if RTE_VERSION < RTE_VERSION_NUM(19,8,0,0)
#define rte_ipv4_hdr ipv4_hdr
#define rte_ether_addr ether_addr
#endif
/**
* Unified type for DPDK port IDs.
* Until DPDK v17.05 was uint8_t
* After DPDK v17.05 has been uint16_t
*/
#if RTE_VERSION >= RTE_VERSION_NUM(17,05,0,0)
typedef uint16_t portid_t;
#else
typedef uint8_t portid_t;
#endif
CLICK_DECLS
class DPDKDeviceArg;
extern bool dpdk_enabled;
class DPDKDevice {
public:
portid_t port_id;
DPDKDevice() CLICK_COLD;
DPDKDevice(portid_t port_id) CLICK_COLD;
int add_rx_queue(
unsigned &queue_id, bool promisc,
unsigned n_desc, ErrorHandler *errh
) CLICK_COLD;
int add_tx_queue(
unsigned &queue_id, unsigned n_desc,
ErrorHandler *errh
) CLICK_COLD;
EtherAddress get_mac();
void set_init_mac(EtherAddress mac);
void set_init_mtu(uint16_t mtu);
unsigned int get_nb_txdesc();
int nbRXQueues();
int nbTXQueues();
const char *get_device_driver();
static unsigned int dev_count() {
#if RTE_VERSION >= RTE_VERSION_NUM(18,05,0,0)
return rte_eth_dev_count_avail();
#else
return rte_eth_dev_count();
#endif
}
static struct rte_mempool *get_mpool(unsigned int);
static int get_port_numa_node(portid_t port_id);
static int initialize(ErrorHandler *errh);
inline static bool is_dpdk_packet(Packet* p) {
return p->buffer_destructor() == DPDKDevice::free_pkt || (p->data_packet() && is_dpdk_packet(p->data_packet()));
}
inline static rte_mbuf* get_pkt(unsigned numa_node);
inline static rte_mbuf* get_pkt();
static void free_pkt(unsigned char *, size_t, void *pktmbuf);
static int NB_MBUF;
static int MBUF_DATA_SIZE;
static int MBUF_SIZE;
static int MBUF_CACHE_SIZE;
static int RX_PTHRESH;
static int RX_HTHRESH;
static int RX_WTHRESH;
static int TX_PTHRESH;
static int TX_HTHRESH;
static int TX_WTHRESH;
static String MEMPOOL_PREFIX;
static unsigned DEF_DEV_RXDESC;
static unsigned DEF_DEV_TXDESC;
static unsigned DEF_BURST_SIZE;
private:
enum Dir { RX, TX };
struct DevInfo {
inline DevInfo() :
rx_queues(0,false), tx_queues(0,false), promisc(false), n_rx_descs(0),
n_tx_descs(0), init_mac(), init_mtu(0) {
rx_queues.reserve(128);
tx_queues.reserve(128);
}
const char* driver;
Vector<bool> rx_queues;
Vector<bool> tx_queues;
bool promisc;
unsigned n_rx_descs;
unsigned n_tx_descs;
EtherAddress init_mac;
uint16_t init_mtu;
};
DevInfo info;
static bool _is_initialized;
static HashTable<portid_t, DPDKDevice> _devs;
static struct rte_mempool** _pktmbuf_pools;
static unsigned _nr_pktmbuf_pools;
static bool no_more_buffer_msg_printed;
int initialize_device(ErrorHandler *errh) CLICK_COLD;
int add_queue(Dir dir, unsigned &queue_id, bool promisc,
unsigned n_desc, ErrorHandler *errh) CLICK_COLD;
static bool alloc_pktmbufs() CLICK_COLD;
static DPDKDevice* get_device(const portid_t &port_id) {
return &(_devs.find_insert(port_id, DPDKDevice(port_id)).value());
}
#if RTE_VERSION < RTE_VERSION_NUM(18,05,0,0)
static int get_port_from_pci(uint32_t domain, uint8_t bus, uint8_t dev_id, uint8_t function) {
struct rte_eth_dev_info dev_info;
uint16_t count = rte_eth_dev_count();
for (portid_t port_id = 0 ; port_id < count; ++port_id) {
rte_eth_dev_info_get(port_id, &dev_info);
struct rte_pci_addr addr = dev_info.pci_dev->addr;
if (addr.domain == domain &&
addr.bus == bus &&
addr.devid == dev_id &&
addr.function == function)
return port_id;
}
return -1;
}
#endif
friend class DPDKDeviceArg;
friend class DPDKInfo;
};
inline rte_mbuf* DPDKDevice::get_pkt(unsigned numa_node) {
struct rte_mbuf* mbuf = rte_pktmbuf_alloc(get_mpool(numa_node));
if (unlikely(!mbuf)) {
if (!DPDKDevice::no_more_buffer_msg_printed)
click_chatter("No more DPDK buffer available ! Try using "
"DPDKInfo to allocate more.");
else
DPDKDevice::no_more_buffer_msg_printed = true;
}
return mbuf;
}
inline rte_mbuf* DPDKDevice::get_pkt() {
return get_pkt(rte_socket_id());
}
/** @class DPDKPortArg
@brief Parser class for DPDK Port, either an integer or a PCI address. */
class DPDKDeviceArg { public:
static bool parse(const String &str, DPDKDevice* &result, const ArgContext &args = ArgContext());
static String unparse(DPDKDevice* dev) {
return String(dev->port_id);
}
};
template<> struct DefaultArg<DPDKDevice*> : public DPDKDeviceArg {};
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,43 @@
// -*- c-basic-offset: 4; related-file-name: "../../lib/driver.cc" -*-
#ifndef CLICK_DRIVER_HH
#define CLICK_DRIVER_HH
#include <click/package.hh>
#define CLICK_DEFAULT_PROVIDES /* nada */
#if defined(CLICK_USERLEVEL) || defined(CLICK_MINIOS)
CLICK_DECLS
class Router;
class Master;
class ErrorHandler;
class Lexer;
struct ArchiveElement;
void click_static_initialize();
void click_static_cleanup();
Lexer *click_lexer();
Router *click_read_router(String filename, bool is_expr, ErrorHandler * = 0, bool initialize = true, Master * = 0);
String click_compile_archive_file(const Vector<ArchiveElement> &ar,
const ArchiveElement *ae,
String package, const String &target, int quiet,
bool &tmpdir_populated, ErrorHandler *errh);
CLICK_ENDDECLS
#elif CLICK_TOOL
CLICK_DECLS
class ErrorHandler;
struct ArchiveElement;
void click_static_initialize();
String click_compile_archive_file(const Vector<ArchiveElement> &archive,
const ArchiveElement *ae,
String package, const String &target, int quiet,
bool &tmpdir_populated, ErrorHandler *errh);
CLICK_ENDDECLS
#endif
#endif

View File

@ -0,0 +1,729 @@
// -*- c-basic-offset: 4; related-file-name: "../../lib/element.cc" -*-
#ifndef CLICK_ELEMENT_HH
#define CLICK_ELEMENT_HH
#include <click/glue.hh>
#include <click/vector.hh>
#include <click/string.hh>
#include <click/packet.hh>
#include <click/handler.hh>
CLICK_DECLS
class Router;
class Master;
class RouterThread;
class Task;
class Timer;
class NotifierSignal;
class Element;
class ErrorHandler;
class Bitvector;
class EtherAddress;
/** @file <click/element.hh>
* @brief Click's Element class.
*/
#ifndef CLICK_ELEMENT_DEPRECATED
# define CLICK_ELEMENT_DEPRECATED CLICK_DEPRECATED
#endif
class Element { public:
Element();
virtual ~Element();
static int nelements_allocated;
// RUNTIME
virtual void push(int port, Packet *p);
virtual Packet *pull(int port) CLICK_WARN_UNUSED_RESULT;
virtual Packet *simple_action(Packet *p);
virtual bool run_task(Task *task); // return true iff did useful work
virtual void run_timer(Timer *timer);
#if CLICK_USERLEVEL
enum { SELECT_READ = 1, SELECT_WRITE = 2 };
virtual void selected(int fd, int mask);
virtual void selected(int fd);
#endif
inline void checked_output_push(int port, Packet *p) const;
inline Packet* checked_input_pull(int port) const;
// ELEMENT CHARACTERISTICS
virtual const char *class_name() const = 0;
virtual const char *port_count() const;
static const char PORTS_0_0[];
static const char PORTS_0_1[];
static const char PORTS_1_0[];
static const char PORTS_1_1[];
static const char PORTS_1_1X2[];
virtual const char *processing() const;
static const char AGNOSTIC[];
static const char PUSH[];
static const char PULL[];
static const char PUSH_TO_PULL[];
static const char PULL_TO_PUSH[];
static const char PROCESSING_A_AH[];
virtual const char *flow_code() const;
static const char COMPLETE_FLOW[];
virtual const char *flags() const;
int flag_value(int flag) const;
virtual void *cast(const char *name);
virtual void *port_cast(bool isoutput, int port, const char *name);
// CONFIGURATION, INITIALIZATION, AND CLEANUP
enum ConfigurePhase {
CONFIGURE_PHASE_FIRST = 0,
CONFIGURE_PHASE_INFO = 20,
CONFIGURE_PHASE_PRIVILEGED = 90,
CONFIGURE_PHASE_DEFAULT = 100,
CONFIGURE_PHASE_LAST = 2000
};
virtual int configure_phase() const;
virtual int configure(Vector<String> &conf, ErrorHandler *errh);
virtual void add_handlers();
virtual int initialize(ErrorHandler *errh);
virtual void take_state(Element *old_element, ErrorHandler *errh);
virtual Element *hotswap_element() const;
enum CleanupStage {
CLEANUP_NO_ROUTER,
CLEANUP_BEFORE_CONFIGURE = CLEANUP_NO_ROUTER,
CLEANUP_CONFIGURE_FAILED,
CLEANUP_CONFIGURED,
CLEANUP_INITIALIZE_FAILED,
CLEANUP_INITIALIZED,
CLEANUP_ROUTER_INITIALIZED,
CLEANUP_MANUAL
};
virtual void cleanup(CleanupStage stage);
static inline void static_initialize();
static inline void static_cleanup();
// ELEMENT ROUTER CONNECTIONS
String name() const;
virtual String declaration() const;
inline Router *router() const;
inline int eindex() const;
inline int eindex(Router *r) const;
/** @brief Return the element's master. */
inline Master *master() const;
inline void attach_router(Router *r, int eindex) {
assert(!_router);
_router = r;
_eindex = eindex;
}
// INPUTS AND OUTPUTS
inline int nports(bool isoutput) const;
inline int ninputs() const;
inline int noutputs() const;
class Port;
inline const Port &port(bool isoutput, int port) const;
inline const Port &input(int port) const;
inline const Port &output(int port) const;
inline bool port_active(bool isoutput, int port) const;
inline bool input_is_push(int port) const;
inline bool input_is_pull(int port) const;
inline bool output_is_push(int port) const;
inline bool output_is_pull(int port) const;
void port_flow(bool isoutput, int port, Bitvector*) const;
// LIVE RECONFIGURATION
String configuration() const;
virtual bool can_live_reconfigure() const;
virtual int live_reconfigure(Vector<String>&, ErrorHandler*);
RouterThread *home_thread() const;
#if CLICK_USERLEVEL
// SELECT
int add_select(int fd, int mask);
int remove_select(int fd, int mask);
#endif
// HANDLERS
void add_read_handler(const String &name, ReadHandlerCallback read_callback, const void *user_data = 0, uint32_t flags = 0);
void add_read_handler(const String &name, ReadHandlerCallback read_callback, int user_data, uint32_t flags = 0);
void add_read_handler(const char *name, ReadHandlerCallback read_callback, int user_data = 0, uint32_t flags = 0);
void add_write_handler(const String &name, WriteHandlerCallback write_callback, const void *user_data = 0, uint32_t flags = 0);
void add_write_handler(const String &name, WriteHandlerCallback write_callback, int user_data, uint32_t flags = 0);
void add_write_handler(const char *name, WriteHandlerCallback write_callback, int user_data = 0, uint32_t flags = 0);
void set_handler(const String &name, int flags, HandlerCallback callback, const void *read_user_data = 0, const void *write_user_data = 0);
void set_handler(const String &name, int flags, HandlerCallback callback, int read_user_data, int write_user_data = 0);
void set_handler(const char *name, int flags, HandlerCallback callback, int read_user_data = 0, int write_user_data = 0);
int set_handler_flags(const String &name, int set_flags, int clear_flags = 0);
enum { TASKHANDLER_WRITE_SCHEDULED = 1,
TASKHANDLER_WRITE_TICKETS = 2,
TASKHANDLER_WRITE_HOME_THREAD = 4,
TASKHANDLER_WRITE_ALL = 7,
TASKHANDLER_DEFAULT = 6 };
void add_task_handlers(Task *task, NotifierSignal *signal, int flags, const String &prefix = String());
inline void add_task_handlers(Task *task, NotifierSignal *signal, const String &prefix = String()) {
add_task_handlers(task, signal, TASKHANDLER_DEFAULT, prefix);
}
inline void add_task_handlers(Task *task, const String &prefix = String()) {
add_task_handlers(task, 0, TASKHANDLER_DEFAULT, prefix);
}
void add_data_handlers(const char *name, int flags, uint8_t *data);
void add_data_handlers(const char *name, int flags, bool *data);
void add_data_handlers(const char *name, int flags, uint16_t *data);
void add_data_handlers(const char *name, int flags, int *data);
void add_data_handlers(const char *name, int flags, unsigned *data);
void add_data_handlers(const char *name, int flags, atomic_uint32_t *data);
void add_data_handlers(const char *name, int flags, long *data);
void add_data_handlers(const char *name, int flags, unsigned long *data);
#if HAVE_LONG_LONG
void add_data_handlers(const char *name, int flags, long long *data);
void add_data_handlers(const char *name, int flags, unsigned long long *data);
#endif
void add_net_order_data_handlers(const char *name, int flags, uint16_t *data);
void add_net_order_data_handlers(const char *name, int flags, uint32_t *data);
#if HAVE_FLOAT_TYPES
void add_data_handlers(const char *name, int flags, double *data);
#endif
void add_data_handlers(const char *name, int flags, String *data);
void add_data_handlers(const char *name, int flags, IPAddress *data);
void add_data_handlers(const char *name, int flags, EtherAddress *data);
void add_data_handlers(const char *name, int flags, Timestamp *data, bool is_interval = false);
static String read_positional_handler(Element*, void*);
static String read_keyword_handler(Element*, void*);
static int reconfigure_positional_handler(const String&, Element*, void*, ErrorHandler*);
static int reconfigure_keyword_handler(const String&, Element*, void*, ErrorHandler*);
virtual int llrpc(unsigned command, void* arg);
int local_llrpc(unsigned command, void* arg);
class Port { public:
inline bool active() const;
inline Element* element() const;
inline int port() const;
inline void push(Packet* p) const;
inline Packet* pull() const;
#if CLICK_STATS >= 1
unsigned npackets() const { return _packets; }
#endif
inline void assign(bool isoutput, Element *e, int port);
private:
Element* _e;
int _port;
#if HAVE_BOUND_PORT_TRANSFER
union {
void (*push)(Element *e, int port, Packet *p);
Packet *(*pull)(Element *e, int port);
} _bound;
#endif
#if CLICK_STATS >= 1
mutable unsigned _packets; // How many packets have we moved?
#endif
#if CLICK_STATS >= 2
Element* _owner; // Whose input or output are we?
#endif
inline Port();
inline void assign(bool isoutput, Element *owner, Element *e, int port);
friend class Element;
};
// DEPRECATED
/** @cond never */
String id() const CLICK_DEPRECATED;
String landmark() const CLICK_DEPRECATED;
/** @endcond never */
private:
enum { INLINE_PORTS = 4 };
Port* _ports[2];
Port _inline_ports[INLINE_PORTS];
int _nports[2];
Router* _router;
int _eindex;
#if CLICK_STATS >= 2
// STATISTICS
unsigned _xfer_calls; // Push and pull calls into this element.
click_cycles_t _xfer_own_cycles; // Cycles spent in self from push and pull.
click_cycles_t _child_cycles; // Cycles spent in children.
unsigned _task_calls; // Calls to tasks owned by this element.
click_cycles_t _task_own_cycles; // Cycles spent in self from tasks.
unsigned _timer_calls; // Calls to timers owned by this element.
click_cycles_t _timer_own_cycles; // Cycles spent in self from timers.
inline void reset_cycles() {
_xfer_calls = _task_calls = _timer_calls = 0;
_xfer_own_cycles = _task_own_cycles = _timer_own_cycles = _child_cycles = 0;
}
static String read_cycles_handler(Element *, void *);
static int write_cycles_handler(const String &, Element *, void *, ErrorHandler *);
#endif
Element(const Element &);
Element &operator=(const Element &);
// METHODS USED BY ROUTER
int set_nports(int, int);
int notify_nports(int, int, ErrorHandler *);
enum Processing { VAGNOSTIC, VPUSH, VPULL };
static int next_processing_code(const char*& p, ErrorHandler* errh);
void processing_vector(int* input_codes, int* output_codes, ErrorHandler*) const;
void initialize_ports(const int* input_codes, const int* output_codes);
int connect_port(bool isoutput, int port, Element*, int);
static String read_handlers_handler(Element *e, void *user_data);
void add_default_handlers(bool writable_config);
inline void add_data_handlers(const char *name, int flags, HandlerCallback callback, void *data);
friend class Router;
#if CLICK_STATS >= 2
friend class Task;
friend class Master;
friend class TimerSet;
# if CLICK_USERLEVEL
friend class SelectSet;
# endif
#endif
};
/** @brief Initialize static data for this element class.
*
* Place initialization code for an element class's shared global state in the
* static_initialize() static member function. (For example, the IPFilter
* element class uses static_initialize() to set up various parsing tables.)
* Click drivers will call this function when the element code is loaded,
* before any elements of the class are created.
*
* static_initialize functions are called in an arbitrary and unpredictable
* order (not, for example, the configure_phase() order). Element authors are
* responsible for handling static initialization dependencies.
*
* For Click to find a static_initialize declaration, it must appear inside
* the element class's class declaration on its own line and have the
* following prototype:
*
* @code
* static void static_initialize();
* @endcode
*
* It must also have public accessibility.
*
* @note In most cases you should also define a static_cleanup() function to
* clean up state initialized by static_initialize().
*
* @sa Element::static_cleanup
*/
inline void
Element::static_initialize()
{
}
/** @brief Clean up static data for this element class.
*
* Place cleanup code for an element class's shared global state in the
* static_cleanup() static member function. Click drivers will call this
* function before unloading the element code.
*
* static_cleanup functions are called in an arbitrary and unpredictable order
* (not, for example, the configure_phase() order, and not the reverse of the
* static_initialize order). Element authors are responsible for handling
* static cleanup dependencies.
*
* For Click to find a static_cleanup declaration, it must appear inside the
* element class's class declaration on its own line and have the following
* prototype:
*
* @code
* static void static_cleanup();
* @endcode
*
* It must also have public accessibility.
*
* @sa Element::static_initialize
*/
inline void
Element::static_cleanup()
{
}
/** @brief Return the element's router. */
inline Router*
Element::router() const
{
return _router;
}
/** @brief Return the element's index within its router.
* @invariant this == router()->element(eindex())
*/
inline int
Element::eindex() const
{
return _eindex;
}
/** @brief Return the element's index within router @a r.
*
* Returns -1 if @a r != router(). */
inline int
Element::eindex(Router* r) const
{
return (router() == r ? _eindex : -1);
}
/** @brief Return the number of input or output ports.
* @param isoutput false for input ports, true for output ports */
inline int
Element::nports(bool isoutput) const
{
return _nports[isoutput];
}
/** @brief Return the number of input ports. */
inline int
Element::ninputs() const
{
return _nports[0];
}
/** @brief Return the number of output ports. */
inline int
Element::noutputs() const
{
return _nports[1];
}
/** @brief Return one of the element's ports.
* @param isoutput false for input ports, true for output ports
* @param port port number
*
* An assertion fails if @a p is out of range. */
inline const Element::Port&
Element::port(bool isoutput, int port) const
{
assert((unsigned) port < (unsigned) _nports[isoutput]);
return _ports[isoutput][port];
}
/** @brief Return one of the element's input ports.
* @param port port number
*
* An assertion fails if @a port is out of range.
*
* @sa Port, port */
inline const Element::Port&
Element::input(int port) const
{
return Element::port(false, port);
}
/** @brief Return one of the element's output ports.
* @param port port number
*
* An assertion fails if @a port is out of range.
*
* @sa Port, port */
inline const Element::Port&
Element::output(int port) const
{
return Element::port(true, port);
}
/** @brief Check whether a port is active.
* @param isoutput false for input ports, true for output ports
* @param port port number
*
* Returns true iff @a port is in range and @a port is active. Push outputs
* and pull inputs are active; pull outputs and push inputs are not.
*
* @sa Element::Port::active */
inline bool
Element::port_active(bool isoutput, int port) const
{
return (unsigned) port < (unsigned) nports(isoutput)
&& _ports[isoutput][port].active();
}
/** @brief Check whether output @a port is push.
*
* Returns true iff output @a port exists and is push. @sa port_active */
inline bool
Element::output_is_push(int port) const
{
return port_active(true, port);
}
/** @brief Check whether output @a port is pull.
*
* Returns true iff output @a port exists and is pull. */
inline bool
Element::output_is_pull(int port) const
{
return (unsigned) port < (unsigned) nports(true)
&& !_ports[1][port].active();
}
/** @brief Check whether input @a port is pull.
*
* Returns true iff input @a port exists and is pull. @sa port_active */
inline bool
Element::input_is_pull(int port) const
{
return port_active(false, port);
}
/** @brief Check whether input @a port is push.
*
* Returns true iff input @a port exists and is push. */
inline bool
Element::input_is_push(int port) const
{
return (unsigned) port < (unsigned) nports(false)
&& !_ports[0][port].active();
}
#if CLICK_STATS >= 2
# define PORT_ASSIGN(o) _packets = 0; _owner = (o)
#elif CLICK_STATS >= 1
# define PORT_ASSIGN(o) _packets = 0; (void) (o)
#else
# define PORT_ASSIGN(o) (void) (o)
#endif
inline
Element::Port::Port()
: _e(0), _port(-2)
{
PORT_ASSIGN(0);
}
inline void
Element::Port::assign(bool isoutput, Element *e, int port)
{
_e = e;
_port = port;
(void) isoutput;
#if HAVE_BOUND_PORT_TRANSFER
if (e) {
if (isoutput) {
void (Element::*pusher)(int, Packet *) = &Element::push;
_bound.push = (void (*)(Element *, int, Packet *)) (e->*pusher);
} else {
Packet *(Element::*puller)(int) = &Element::pull;
_bound.pull = (Packet *(*)(Element *, int)) (e->*puller);
}
}
#endif
}
inline void
Element::Port::assign(bool isoutput, Element *owner, Element *e, int port)
{
PORT_ASSIGN(owner);
assign(isoutput, e, port);
}
/** @brief Returns whether this port is active (a push output or a pull input).
*
* @sa Element::port_active
*/
inline bool
Element::Port::active() const
{
return _port >= 0;
}
/** @brief Returns the element connected to this active port.
*
* Returns 0 if this port is not active(). */
inline Element*
Element::Port::element() const
{
return _e;
}
/** @brief Returns the port number of the port connected to this active port.
*
* Returns < 0 if this port is not active(). */
inline int
Element::Port::port() const
{
return _port;
}
/** @brief Push packet @a p over this port.
*
* Pushes packet @a p downstream through the router configuration by passing
* it to the next element's @link Element::push() push() @endlink function.
* Returns when the rest of the router finishes processing @a p.
*
* This port must be an active() push output port. Usually called from
* element code like @link Element::output output(i) @endlink .push(p).
*
* When element code calls Element::Port::push(@a p), it relinquishes control
* of packet @a p. When push() returns, @a p may have been altered or even
* freed by downstream elements. Thus, you must not use @a p after pushing it
* downstream. To push a copy and keep a copy, see Packet::clone().
*
* output(i).push(p) basically behaves like the following code, although it
* maintains additional statistics depending on how CLICK_STATS is defined:
*
* @code
* output(i).element()->push(output(i).port(), p);
* @endcode
*/
inline void
Element::Port::push(Packet* p) const
{
assert(_e && p);
#if CLICK_STATS >= 1
++_packets;
#endif
#if CLICK_STATS >= 2
++_e->input(_port)._packets;
click_cycles_t start_cycles = click_get_cycles(),
start_child_cycles = _e->_child_cycles;
# if HAVE_BOUND_PORT_TRANSFER
_bound.push(_e, _port, p);
# else
_e->push(_port, p);
# endif
click_cycles_t all_delta = click_get_cycles() - start_cycles,
own_delta = all_delta - (_e->_child_cycles - start_child_cycles);
_e->_xfer_calls += 1;
_e->_xfer_own_cycles += own_delta;
_owner->_child_cycles += all_delta;
#else
# if HAVE_BOUND_PORT_TRANSFER
_bound.push(_e, _port, p);
# else
_e->push(_port, p);
# endif
#endif
}
/** @brief Pull a packet over this port and return it.
*
* Pulls a packet from upstream in the router configuration by calling the
* previous element's @link Element::pull() pull() @endlink function. When
* the router finishes processing, returns the result.
*
* This port must be an active() pull input port. Usually called from element
* code like @link Element::input input(i) @endlink .pull().
*
* input(i).pull() basically behaves like the following code, although it
* maintains additional statistics depending on how CLICK_STATS is defined:
*
* @code
* input(i).element()->pull(input(i).port())
* @endcode
*/
inline Packet*
Element::Port::pull() const
{
assert(_e);
#if CLICK_STATS >= 2
click_cycles_t start_cycles = click_get_cycles(),
old_child_cycles = _e->_child_cycles;
# if HAVE_BOUND_PORT_TRANSFER
Packet *p = _bound.pull(_e, _port);
# else
Packet *p = _e->pull(_port);
# endif
if (p)
_e->output(_port)._packets += 1;
click_cycles_t all_delta = click_get_cycles() - start_cycles,
own_delta = all_delta - (_e->_child_cycles - old_child_cycles);
_e->_xfer_calls += 1;
_e->_xfer_own_cycles += own_delta;
_owner->_child_cycles += all_delta;
#else
# if HAVE_BOUND_PORT_TRANSFER
Packet *p = _bound.pull(_e, _port);
# else
Packet *p = _e->pull(_port);
# endif
#endif
#if CLICK_STATS >= 1
if (p)
++_packets;
#endif
return p;
}
/** @brief Push packet @a p to output @a port, or kill it if @a port is out of
* range.
*
* @param port output port number
* @param p packet to push
*
* If @a port is in range (>= 0 and < noutputs()), then push packet @a p
* forward using output(@a port).push(@a p). Otherwise, kill @a p with @a p
* ->kill().
*
* @note It is invalid to call checked_output_push() on a pull output @a port.
*/
inline void
Element::checked_output_push(int port, Packet* p) const
{
if ((unsigned) port < (unsigned) noutputs())
_ports[1][port].push(p);
else
p->kill();
}
/** @brief Pull a packet from input @a port, or return 0 if @a port is out of
* range.
*
* @param port input port number
*
* If @a port is in range (>= 0 and < ninputs()), then return the result
* of input(@a port).pull(). Otherwise, return null.
*
* @note It is invalid to call checked_input_pull() on a push input @a port.
*/
inline Packet*
Element::checked_input_pull(int port) const
{
if ((unsigned) port < (unsigned) ninputs())
return _ports[0][port].pull();
else
return 0;
}
#undef PORT_ASSIGN
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,64 @@
// -*- c-basic-offset: 4; related-file-name: "../../lib/elemfilter.cc" -*-
#ifndef CLICK_ELEMFILTER_HH
#define CLICK_ELEMFILTER_HH
#include <click/element.hh>
CLICK_DECLS
class ElementFilter { public:
/** @brief Construct an ElementFilter. */
ElementFilter() {
}
/** @brief Destroy an ElementFilter. */
virtual ~ElementFilter() {
}
/** @brief Determine whether an element or port matches this filter.
* @param e element
* @param isoutput true for output ports, false for input ports
* @param port port number, or -1 to check the element as a whole
*
* This virtual function is the core of ElementFilter's functionality.
* The function should return true iff the specified element or port
* matches the filter. @a isoutput and @a port define the interesting
* port; if @a port < 0, the element should be checked as a whole.
*
* The default implementation returns false for any element.
*/
virtual bool check_match(Element *e, bool isoutput, int port);
/** @brief Remove all non-matching elements from @a es.
* @param es array of elements
*
* Calls check_match(e, false, -1) for each element of @a es, removing
* those elements that do not match (i.e., check_match() returns false).
*/
void filter(Vector<Element *> &es);
};
class CastElementFilter : public ElementFilter { public:
/** @brief Construct a CastElementFilter.
* @param name cast name of matching elements
*/
CastElementFilter(const String &name);
/** @brief Determine whether an element matches this filter.
* @param e element
* @param isoutput ignored
* @param port ignored
* @return True iff @a e->cast(@a name) != NULL, where @a name is the
* cast name passed to the constructor.
*/
bool check_match(Element *e, bool isoutput, int port);
private:
String _name;
};
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,887 @@
// -*- related-file-name: "../../lib/error.cc" -*-
#ifndef CLICK_ERROR_HH
#define CLICK_ERROR_HH
#include <click/string.hh>
#if defined(CLICK_USERLEVEL) || defined(CLICK_TOOL) || defined(CLICK_MINIOS)
# include <stdio.h>
#endif
#if CLICK_BSDMODULE
# include <machine/stdarg.h>
#else
# include <stdarg.h>
#endif
#if HAVE_ADDRESSABLE_VA_LIST
# define VA_LIST_REF_T va_list *
# define VA_LIST_DEREF(val) (*(val))
# define VA_LIST_REF(val) (&(val))
#else
# define VA_LIST_REF_T va_list
# define VA_LIST_DEREF(val) (val)
# define VA_LIST_REF(val) (val)
#endif
#if __GNUC__ <= 3
# define ERRH_SENTINEL
#else
# define ERRH_SENTINEL __attribute__((sentinel))
#endif
CLICK_DECLS
/** @class ErrorHandler
* @brief Error reporting class.
*
* Click elements report errors through ErrorHandler objects, which represent
* error collectors and printers. ErrorHandlers are passed to configure() and
* initialize() methods explicitly, as well as to write handlers; the
* click_chatter() function calls ErrorHandler implicitly.
*
* <h3>Cooked error messages</h3>
*
* Most ErrorHandler interactions consist of a simple call like this:
* @code
* errh->error("not enough arguments (%d needed)", 5);
* // prints something like "not enough arguments (5 needed)\n"
* @endcode
*
* This function constructs an error message string from the format arguments,
* annotates the string with a default error level (here, el_error), and
* prints it. Alternate versions take a landmark specifying where the error
* took place:
* @code
* errh->lwarning("file.click:2", "syntax error at '%s'", word.c_str());
* // prints something like "file.click:2: syntax error at 'foo'\n"
* @endcode
*
* <h3>Raw error messages</h3>
*
* For finer control over error levels and annotations, construct an error
* message string directly. An error message is a string consisting of one or
* more lines. Each line begins with a set of optional textual @em
* annotations. The following error message has a @em level annotation
* determining how serious the error is (this one is critical, since
* el_critical == 2), and a @em landmark annotation, which specifies where the
* error took place (here, "x.click:1"):
*
* <tt>"<2>{l:x.click:1}syntax error"</tt>
*
* Click's default ErrorHandlers understand the level and landmark
* annotations. Users can add other arbitrary annotations, which can be
* useful to pass error metadata. A pair of braces ends the annotation area.
* This example has one user annotation <tt>eoc</tt>, and a message area that
* would be mistaken for an annotation were it not for the <tt>{}</tt>:
*
* <tt>"<2>{l:x.click:1}{eoc:520}{}{not:an annotation}"</tt>
*
* <h3>Stacking handlers</h3>
*
* Some ErrorHandlers stack on top of others, adding useful functionality like
* automatic context description and prefixing. For example,
* ContextErrorHandler can be used to print messages like "In function
* 'xxx':".
* @code
* FileErrorHandler errh1(stderr);
* ContextErrorHandler errh2(&errh1, "While counting to 2:");
* errh2.error("An error occurred.");
* errh2.error("Another error occurred.");
* // prints "While counting to 2:\n"
* // " An error occurred.\n"
* // " Another error occurred.\n"
* @endcode */
class ErrorHandler { public:
/** @brief Error level constants.
*
* Lower values represent more serious errors. Levels 0-7 correspond to
* Linux's error levels. Negative levels request immediate exit; at user
* level, the Click process's exit status is the absolute value of the
* error level. */
enum Level {
el_abort = -999, ///< Error level that triggers abort().
el_fatal = -1, ///< Fatal exit error level.
/// Exit status equals -(level).
el_emergency = 0, ///< Emergency error level: system is unusable.
el_alert = 1, ///< Alert error level: action must be taken.
el_critical = 2, ///< Error level for critical conditions.
el_error = 3, ///< Error level for normal error conditions.
el_warning = 4, ///< Error level for warning conditions.
el_notice = 5, ///< Error level for normal, but significant
/// conditions.
el_info = 6, ///< Error level for informational messages.
el_debug = 7 ///< Error level for debug messages.
};
/** @brief Error level indicators. */
static const char e_abort[],
e_fatal[],
e_emergency[],
e_alert[],
e_critical[],
e_error[],
e_warning[],
e_warning_annotated[],
e_notice[],
e_info[],
e_debug[];
/** @brief Construct an ErrorHandler. */
ErrorHandler()
: _nerrors(0) {
}
virtual ~ErrorHandler() {
}
/** @brief Initialize the ErrorHandler implementation.
* @param errh default error handler
* @return @a errh
*
* Call this function to initialize the ErrorHandler implementation. The
* function installs the default conversions, creates the
* silent_handler(), and installs @a errh as the default error handler
* (see default_handler()).
*
* @note The @a errh object becomes the property of the ErrorHandler
* implementation and must not be deleted.
* (ErrorHandler::static_cleanup() will delete it.) Only the first call
* to static_initialize() has any effect. */
static ErrorHandler *static_initialize(ErrorHandler *errh);
/** @brief Tear down the ErrorHandler implementation.
*
* Deletes the internal ErrorHandlers and uninstalls default
* conversions. */
static void static_cleanup();
/** @brief Return the default ErrorHandler.
* @sa static_initialize() */
static ErrorHandler *default_handler() {
return the_default_handler;
}
/** @brief Set the default ErrorHandler to @a errh.
* @note @a errh becomes property of the ErrorHandler implementation,
* and will be freed by static_cleanup(). However, any prior default
* handler is @em not destroyed. Callers should delete the prior handler
* when necessary. */
static void set_default_handler(ErrorHandler *errh);
/** @brief Return the global silent ErrorHandler. */
static ErrorHandler *silent_handler() {
return the_silent_handler;
}
static const int ok_result; ///< Equals 0, used for error levels
/// <5> and above
static const int error_result; ///< Equals -EINVAL, used for error
/// levels <4> and below
/** @brief Print a debug message (level el_debug).
*
* @a fmt and any following arguments are parsed as by format(), and the
* resulting string is passed to xmessage(). */
void debug(const char *fmt, ...);
/** @brief Print an informational message (level el_info). */
void message(const char *fmt, ...);
/** @brief Print a warning message (level el_warning).
* @return error_result
*
* The string "warning: " is prepended to every line of the message. */
int warning(const char *fmt, ...);
/** @brief Print an error message (level el_error).
* @return error_result */
int error(const char *fmt, ...);
/** @brief Print a fatal error message (level el_fatal).
* @return error_result
*
* In many ErrorHandlers, calling fatal() will cause Click to abort. */
int fatal(const char *fmt, ...);
/** @brief Print a debug message with a landmark annotation. */
void ldebug(const String &landmark, const char *fmt, ...);
/** @brief Print an informational message with a landmark annotation. */
void lmessage(const String &landmark, const char *fmt, ...);
/** @brief Print a warning message with a landmark annotation. */
int lwarning(const String &landmark, const char *fmt, ...);
/** @brief Print an error message with a landmark annotation. */
int lerror(const String &landmark, const char *fmt, ...);
/** @brief Print a fatal error message with a landmark annotation. */
int lfatal(const String &landmark, const char *fmt, ...);
/** @brief Print an annotated error message.
* @return ok_result if the minimum error level was el_notice or higher,
* otherwise error_result
*
* This function drives the virtual functions actually responsible for
* error message decoration and printing. It passes @a str to decorate(),
* separates the result into lines, calls emit() for each line, and calls
* account() with the minimum error level of any line.
*
* Most users will call shorthand functions like error(), warning(), or
* lmessage(), which add relevant annotations to the message. */
int xmessage(const String &str);
/** @brief Print an error message, adding annotations.
* @param anno annotations
* @param str error message
*
* Shorthand for xmessage(combine_anno(@a str, @a anno)). */
int xmessage(const String &anno, const String &str) {
return xmessage(combine_anno(str, anno));
}
/** @brief Format and print an error message, adding annotations.
* @param anno annotations
* @param fmt error message format
* @param val format arguments
*
* Shorthand for xmessage(@a anno, vformat(@a fmt, @a val)). */
int xmessage(const String &anno, const char *fmt, va_list val) {
return xmessage(anno, vformat(fmt, val));
}
/** @brief Print an error message, adding landmark and other annotations.
* @param landmark landmark annotation
* @param anno additional annotations
* @param str error message
*
* Shorthand for xmessage(combine_anno(@a anno, make_landmark_anno(@a
* landmark)), @a str). */
int xmessage(const String &landmark, const String &anno,
const String &str) {
return xmessage(combine_anno(anno, make_landmark_anno(landmark)), str);
}
/** @brief Format and print an error message, adding landmark and other
* annotations.
* @param landmark landmark annotation
* @param anno additional annotations
* @param fmt error message format
* @param val format arguments
*
* Shorthand for xmessage(@a landmark, @a anno, vformat(@a fmt, @a
* val)). */
int xmessage(const String &landmark, const String &anno,
const char *fmt, va_list val) {
return xmessage(landmark, anno, vformat(fmt, val));
}
/** @brief Return the number of errors reported via this handler.
*
* An error is any message that contains at least one line with error
* level 3 (#el_error) or below.
*
* @note The error count will also contain errors reported via stacked
* handlers. For instance:
* @code
* SilentErrorHandler errh1;
* PrefixErrorHandler errh2(&errh1, "");
* assert(errh1.nerrors() == 0);
* errh2.error("blah");
* assert(errh1.nerrors() == 1);
* @endcode
*
* @sa account, clear */
int nerrors() const {
return _nerrors;
}
/** @brief Format an error string.
* @param default_flags default ConversionFlags
* @param fmt printf-like format string
* @return formatted error string
*
* Formats an error string using printf-like % conversions. Conversions
* include:
*
* <table>
*
* <tr><td><tt>\%d</tt>, <tt>\%i</tt></td><td>Format an <tt>int</tt> as a
* decimal string. Understands flags in <tt>#0- +</tt>, field widths
* (including <tt>*</tt>), and precisions.</td></tr>
*
* <tr><td><tt>\%hd</tt>, <tt>\%ld</tt>, <tt>\%lld</tt>,
* <tt>\%zd</tt></td><td>Format a <tt>short</tt>, <tt>long</tt>, <tt>long
* long</tt>, or <tt>size_t</tt>.</td></tr>
*
* <tr><td><tt>\%^16d</tt>, <tt>\%^32d</tt>, <tt>\%^64d</tt></td>
* <td>Format a 16-, 32-, or 64-bit integer.</td></tr>
*
* <tr><td><tt>\%o</tt>, <tt>\%u</tt>, <tt>\%x</tt>,
* <tt>\%X</tt></td><td>Format an unsigned integer in octal, decimal, or
* hexadecimal (with lower-case or upper-case letters).</td></tr>
*
* <tr><td><tt>\%s</tt></td><td>Format a C string (<tt>const char *</tt>).
* The alternate form <tt>\%\#s</tt> calls String::printable() on the
* input string. Both <tt>\%\#s</tt> and the alternate form <tt>\%'s</tt>
* ensure that no part of the string is mistaken for an error
* annotation.</td></tr>
*
* <tr><td><tt>\%c</tt></td><td>Format a character. Prints a C-like
* escape if the input character isn't printable ASCII.</td></tr>
*
* <tr><td><tt>\%p</tt></td><td>Format a pointer as a hexadecimal
* value.</td></tr>
*
* <tr><td><tt>\%e</tt>, <tt>\%E</tt>, <tt>\%f</tt>, <tt>\%F</tt>,
* <tt>\%g</tt>, <tt>\%G</tt></td><td>Format a <tt>double</tt> (user-level
* only).</td></tr>
*
* <tr><td><tt>\%p{...}</tt><td>Call a user-provided conversion function.
* For example, <tt>\%p{ip_ptr}</tt> reads an <tt>IPAddress *</tt> argument
* from the argument list, and formats the pointed-to address using
* IPAddress::unparse().</td></tr>
*
* <tr><td><tt>\%\%</tt></td><td>Format a literal \% character.</td></tr>
*
* <tr><td><tt>\%\<</tt></td><td>Format a left quote string. Usually
* prints a single quote.</td></tr>
*
* <tr><td><tt>\%\></tt></td><td>Format a right quote string. Usually
* prints a single quote.</td></tr>
*
* <tr><td><tt>\%,</tt></td><td>Format an apostrophe string. Usually
* prints a single quote.</td></tr>
*
* </table> */
static String xformat(int default_flags, const char *fmt, ...);
/** @overload */
static String vxformat(int default_flags, const char *fmt, va_list val);
/** @overload */
static String xformat(const char *fmt, ...);
/** @overload */
static String vxformat(const char *fmt, va_list val) {
return vxformat(0, fmt, val);
}
/** @brief Format an error string.
* @param fmt format string
* @param val argument list
*
* @warning ErrorHandler users don't need to call this function directly;
* it is called implicitly by the error()/xmessage() functions.
*
* This virtual function is called to format an error message. The
* default implementation returns the result of vxformat(@a fmt, @a val). */
virtual String vformat(const char *fmt, va_list val);
/** @brief Format an error string.
* @param fmt format string
*
* @warning ErrorHandler users don't usually need to call this function
* directly.
*
* This is a convenience function that calls vformat(const char *fmt,
* va_list val) for a va_list taken from the ellipsis arguments. */
String format(const char *fmt, ...);
/** @brief Decorate an error message.
* @param str error message, possibly with annotations
* @return decorated error message
*
* @warning ErrorHandler users don't need to call this function directly;
* it is called implicitly by the error()/xmessage() functions.
*
* This virtual function is called to decorate an error message before it
* is emitted. The input @a str is an error message string, possibly
* annotated. The default implementation returns @a str unchanged. Other
* ErrorHandlers might add context lines (ContextErrorHandler), prefixes
* (PrefixErrorHandler), or a default landmark (LandmarkErrorHandler). */
virtual String decorate(const String &str);
/** @brief Output an error message line.
* @param str error message line, possibly with annotations
* @param user_data callback data, 0 for first line in a message
* @param more true iff this is the last line in the current message
* @return @a user_data to be passed to emit() for the next line
*
* @warning ErrorHandler users don't need to call this function directly;
* it is called implicitly by the error()/xmessage() functions.
*
* After calling decorate(), ErrorHandler splits the message into
* individual lines and calls emit() once per line. ErrorHandler
* subclasses should output the error lines as appropriate; for example,
* FileErrorHandler outputs the error message to a file.
*
* @a str does not contain a newline, but may contain annotations,
* including a landmark annotation. Most ErrorHandlers use parse_anno()
* to extract the landmark annotation, clean it with clean_landmark(), and
* print it ahead of the error message proper.
*
* ErrorHandler can handle multi-line error messages. However, the emit()
* function takes a line at a time; this is more useful in practice for
* most error message printers. The @a user_data and @a more arguments
* can help an ErrorHandler combine the lines of a multi-line error
* message. @a user_data is null for the first line; for second and
* subsequent lines, ErrorHandler passes the result of the last line's
* emit() call. @a more is true iff this is the last line in the current
* message.
*
* The default emit() implementation does nothing. */
virtual void *emit(const String &str, void *user_data, bool more);
/** @brief Account for an error message at level @a level.
* @param level minimum error level in the message
*
* @warning ErrorHandler users don't need to call this function directly;
* it is called implicitly by the error()/xmessage() functions.
*
* After calling emit() for the lines of an error message, ErrorHandler
* calls account(), passing the minimum (worst) error level of any message
* line (or 1000 if no line had a level). The default implementation
* updates the nerrors() counter. Some other ErrorHandlers
* add account() behavior that, for example, exits after printing messages
* at el_fatal level or below. */
virtual void account(int level) {
if (level <= el_error)
++_nerrors;
}
/** @brief Clear accumulated error state.
*
* The default implementation sets the nerrors() counter to zero. */
virtual void clear() {
_nerrors = 0;
}
/** @brief Create an error annotation.
* @param name annotation name
* @param value annotation value
* @return annotation string
*
* Returns an error annotation that associates annotation @a name with @a
* value.
*
* If @a name equals "<>", then returns a level annotation of the form
* "<@a value>". @a value must be valid number; if it isn't, the function
* returns the empty string.
*
* Otherwise, @a name must be a nonempty series of letters and digits.
* make_anno() returns a string of the form "{@a name:@a value}", where
* special characters in @a value are quoted with backslashes. */
static String make_anno(const char *name, const String &value);
/** @brief Apply annotations from @a anno to every line in @a str.
* @param str string
* @param anno annotation string
*
* The annotations from @a anno are applied to every line in @a str. New
* annotations do not override existing annotations with the same names.
* If the @a anno string ends with non-annotation characters, this
* substring is prefixed to every line in @a str.
*
* For example:
* @code
* combine_anno("Line 1\n{l:old}{x:x}Line 2\n", "<0>{l:new} ")
* // returns "<0>{l:new} Line 1\n<0>{l:old}{x:x} Line 2\n"
* @endcode */
static String combine_anno(const String &str, const String &anno);
/** @brief Parse error annotations from a string.
* @param str the string
* @param begin pointer within @a str to start of annotation area
* @param end pointer to end of error region, usually @a str.end()
* @return pointer to first character after annotation area
* @pre @a str.begin() <= {@a begin, @a end} <= @a str.end()
* @post @a begin <= returned value <= @a end
*
* Use this function to skip an error line's annotation area, possibly
* extracting named annotations.
*
* The variable arguments portion consists of a series of pairs of C
* strings and value pointers, terminated by a null character pointer.
* Each C string is an annotation name. The corresponding annotation
* value, if found, is stored as a String object in the value pointer.
* You can also store the <tt>int</tt> value of an annotation by prefixing
* an annotation name with the '#' character.
*
* For example:
* @code
* String line = "{l:file:30}<4.5>error message\n";
* String landmark_str, level_str;
* const char *s = ErrorHandler::parse_anno(line, line.begin(), line.end(),
* "l", &landmark_str, "<>", &level_str, (const char *) 0);
* // Results: s points to "error message\n",
* // landmark_str == "file:30", level_str == "4.5"
*
* int level;
* s = ErrorHandler::parse_anno(line, line.begin(), line.end(),
* "#<>", &level, (const char *) 0);
* // Results: s points to "error message\n", level_str == 4
* @endcode */
static const char *parse_anno(const String &str,
const char *begin, const char *end, ...) ERRH_SENTINEL;
/** @brief Skip a string's error annotations.
* @param begin pointer to start of string
* @param end pointer one past end of string
* @return pointer to first character after annotation area
* @post @a begin <= returned value <= @a end
*
* Use this function to skip an error line's annotation area. The error
* line is defined as a pair of iterators. */
static const char *skip_anno(const char *begin, const char *end) {
String name, value;
const char *x = begin;
do {
x = skip_anno(String(), x, end, &name, &value, false);
} while (name);
return x;
}
/** @brief Return a landmark annotation equal to @a x.
* @param x landmark
*
* If @a x is empty, returns the empty string. Otherwise, if @a x looks
* like a formatted annotation (it starts with an open brace), returns @a
* x unchanged. Otherwise, returns make_anno("l", @a x). */
static String make_landmark_anno(const String &x) {
if (x && x[0] == '{')
return x;
else if (x)
return make_anno("l", x);
else
return String();
}
/** @brief Clean the @a landmark.
* @param landmark landmark text
* @param colon if true, append <tt>": "</tt> to a nonempty landmark
*
* Removes trailing space and an optional trailing colon from @a landmark
* and returns the result. If @a colon is true, and the cleaned landmark
* isn't the empty string, then appends <tt>": "</tt> to the result. */
static String clean_landmark(const String &landmark, bool colon = false);
// error conversions
struct Conversion;
typedef String (*ConversionFunction)(int flags, VA_LIST_REF_T);
enum ConversionFlags {
cf_zero_pad = 1, ///< Set for conversions using the '0' flag.
cf_plus_positive = 2, ///< Set for conversions using the '+' flag.
cf_space_positive = 4, ///< Set for conversions using the ' ' flag.
cf_left_just = 8, ///< Set for conversions using the '-' flag.
cf_alternate_form = 16, ///< Set for conversions using the '#' flag.
cf_singlequote = 32, ///< Set for conversions using the '\'' flag.
cf_uppercase = 64, ///< Set for 'X' conversions (not 'x').
cf_signed = 128, ///< Set for conversions of signed numbers.
cf_negative = 256, ///< Set for conversions of negative numbers.
cf_utf8 = 1024 ///< Set to use UTF-8 characters on output.
};
static Conversion *add_conversion(const String &name, ConversionFunction func);
static int remove_conversion(Conversion *conversion);
private:
int _nerrors;
static ErrorHandler *the_default_handler;
static ErrorHandler *the_silent_handler;
static const char *skip_anno(const String &str,
const char *begin, const char *end,
String *name_result, String *value_result,
bool raw);
};
/** @class SilentErrorHandler
* @brief An ErrorHandler that does not report messages.
*
* Use SilentErrorHandler when an ErrorHandler object is required, but error
* messages should not be printed. */
class SilentErrorHandler : public ErrorHandler { public:
SilentErrorHandler() {
}
};
/** @class ErrorVeneer
* @brief Base class for ErrorHandlers that forward messages.
*
* ErrorHandlers can stack. Stacking ErrorHandlers simplify modify a message
* and then pass the result to a base ErrorHandler, which does the actual
* printing. The ErrorVeneer base class simplifies the implementation of
* stacking ErrorHandlers. It provides versions of ErrorHandler's format(),
* decorate(), emit(), and account() methods that forward to the underlying
* handler. Note that the clear() method is <em>not</em> automatically
* forwarded. */
class ErrorVeneer : public ErrorHandler { public:
/** @brief Construct an ErrorVeneer.
* @param errh base ErrorHandler
*
* If @a errh is 0, then the ErrorVeneer acts like a
* SilentErrorHandler. */
ErrorVeneer(ErrorHandler *errh)
: _errh(errh) {
}
String vformat(const char *fmt, va_list val);
String decorate(const String &str);
void *emit(const String &str, void *user_data, bool more);
void account(int level);
private:
ErrorHandler *_errh;
};
#if defined(CLICK_USERLEVEL) || defined(CLICK_TOOL) || defined(CLICK_MINIOS)
/** @class FileErrorHandler
* @brief An ErrorHandler that prints error messages to a given file.
*
* FileErrorHandler is the typical base ErrorHandler used at user level. It
* prints messages to a file passed in to the constructor, and calls exit() or
* abort() based on the error level. */
class FileErrorHandler : public ErrorHandler { public:
/** @brief Construct a FileErrorHandler.
* @param f file to print errors
* @param prefix string to prefix every error line */
FileErrorHandler(FILE *f, const String &prefix = String());
void set_default_flags(int default_flags) {
_default_flags = default_flags;
}
String vformat(const char *fmt, va_list val);
void *emit(const String &str, void *user_data, bool more);
void account(int level);
private:
FILE *_f;
String _context;
int _default_flags;
};
#endif
/** @class LocalErrorHandler
* @brief A convenience stackable ErrorHandler.
*
* It's often convenient to pass a null ErrorHandler pointer when errors
* should not be printed. The LocalErrorHandler class simplifies dealing with
* ErrorHandler pointers that may or may not be null. LocalErrorHandler is a
* transparent layer on the base handler; but if the base handler is null, it
* acts like a SilentErrorHandler. For example:
* @code
* void f(ErrorHandler *errh) { // errh might or might not be null
* LocalErrorHandler lerrh(errh);
* ... lerrh.message("message") ...
* }
* @endcode */
class LocalErrorHandler : public ErrorVeneer { public:
/** @brief Construct a LocalErrorHandler. */
LocalErrorHandler(ErrorHandler *errh)
: ErrorVeneer(errh) {
}
};
/** @class ContextErrorHandler
* @brief A stackable ErrorHandler that prints context lines.
*
* The stackable ContextErrorHandler adds context to the first error
* message printed, and optionally indent error messages so that they appear
* grouped underneath the context.
* @code
* FileErrorHandler errh1(stderr);
* ContextErrorHandler errh2(&errh1, "While counting to 2:");
* errh2.error("An error occurred.");
* errh2.error("Another error occurred.");
* // prints "While counting to 2:\n"
* // " An error occurred.\n"
* // " Another error occurred.\n"
* @endcode
*
* To prevent ContextErrorHandler from indenting or printing context for a
* message, add a "{context:no}" annotation to the message's first line. To
* turn off the indent but keep the context, add a "{context:noindent}"
* annotation.
* @code
* FileErrorHandler errh1(stderr);
* ContextErrorHandler errh2(&errh1, "While counting to 2:");
* errh2.error("{context:no}An error occurred.");
* errh2.error("Another error occurred.");
* // prints "An error occurred.\n"
* // "While counting to 2:\n"
* // " Another error occurred.\n"
*
* FileErrorHandler errh1(stderr);
* PrefixErrorHandler noctx_errh(stderr, "{context:no}");
* ContextErrorHandler errh2(&errh1, "While counting to 2:");
* errh2.error("An error occurred.");
* errh2.error("Another error occurred.");
* // prints "An error occurred.\n"
* // "Another error occurred.\n"
* @endcode
*
* ContextErrorHandler adds the "{context:context}" annotation to context
* lines. */
class ContextErrorHandler : public ErrorVeneer { public:
/** @brief Construct a ContextErrorHandler.
* @param errh base ErrorHandler
* @param fmt format for context lines
*
* The context message is formed by @a errh->format() using @a fmt and
* any additional arguments. */
ContextErrorHandler(ErrorHandler *errh, const char *fmt, ...);
/** @brief Return true iff the context has already been printed. */
bool context_printed() const {
return _context_printed;
}
/** @brief Set whether the context has been printed. */
void set_context_printed(bool x) {
_context_printed = x;
}
/** @brief Set the context string to @a str. */
void set_context(const String &str) {
_context = str;
}
/** @brief Set the indent string to @a str.
*
* The indent string is prepended to all non-context messages. It can
* contain landmarks as well as non-landmark text. The default indent
* string is " " (two spaces). */
void set_indent(const String &str) {
_indent = str;
}
/** @brief Set the context landmark to @a str.
*
* The context landmark is used to decorate the context, and also applied
* to any error messages that lack landmarks of their own. The default
* context landmark is empty.
*
* @note The input @a str is passed to
* ErrorHandler::make_landmark_anno(). */
void set_context_landmark(const String &str) {
_context_landmark = make_landmark_anno(str);
}
String decorate(const String &str);
private:
String _context;
String _indent;
String _context_landmark;
bool _context_printed;
};
/** @class PrefixErrorHandler
* @brief A stackable ErrorHandler that adds a prefix to error messages.
*
* The stackable ContextErrorHandler adds a prefix to every error line
* printed. For example:
* @code
* FileErrorHandler errh1(stderr);
* PrefixErrorHandler errh2(&errh1, "Blah--");
* errh2.error("An error occurred.");
* errh2.error("Another error occurred.");
* // prints "Blah--An error occurred.\n"
* // "Blah--Another error occurred.\n"
* @endcode */
class PrefixErrorHandler : public ErrorVeneer { public:
/** @brief Construct a PrefixErrorHandler.
* @param errh base ErrorHandler
* @param prefix string to prefix to error lines */
PrefixErrorHandler(ErrorHandler *errh, const String &prefix);
String decorate(const String &str);
private:
String _prefix;
};
/** @class LandmarkErrorHandler
* @brief A stackable ErrorHandler that adds a default landmark to error
* messages.
*
* The stackable ContextErrorHandler adds a default landmark to every error
* line printed. Error lines' own landmarks are preserved when they exist.
* For example:
* @code
* FileErrorHandler errh1(stderr);
* LandmarkErrorHandler errh2(&errh1, "file:1");
* errh2.error("An error occurred.");
* errh2.lerror("file:2", "Another error occurred.");
* // prints "file:1: An error occurred.\n"
* // "file:2: Another error occurred.\n"
* @endcode */
class LandmarkErrorHandler : public ErrorVeneer { public:
/** @brief Construct a LandmarkErrorHandler.
* @param errh base ErrorHandler
* @param landmark default landmark */
LandmarkErrorHandler(ErrorHandler *errh, const String &landmark);
/** @brief Set the default landmark applied to error messages. */
void set_landmark(const String &landmark) {
_landmark = make_landmark_anno(landmark);
}
String decorate(const String &str);
private:
String _landmark;
};
#if defined(CLICK_USERLEVEL) || defined(CLICK_TOOL) || defined(CLICK_MINIOS)
/** @class BailErrorHandler
* @brief A stackable ErrorHandler that exits when errors occur.
*
* The stackable BailErrorHandler, available only at user level, causes the
* Click process to exit if an error worse than a configurable level occurs. */
class BailErrorHandler : public ErrorVeneer { public:
/** @brief Construct a BailErrorHandler.
* @param errh base ErrorHandler
* @param level error level that causes premature exit
*
* An error message with level less than or equal to @a el_error will
* cause the process to exit with status 1. */
BailErrorHandler(ErrorHandler *errh, int level = el_error);
void account(int level);
private:
int _level;
};
#endif
#undef ERRH_SENTINEL
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,230 @@
// -*- related-file-name: "../../lib/etheraddress.cc" -*-
#ifndef CLICK_ETHERADDRESS_HH
#define CLICK_ETHERADDRESS_HH
#include <click/string.hh>
#include <click/glue.hh>
#include <click/type_traits.hh>
CLICK_DECLS
class EtherAddress { public:
typedef uninitialized_type uninitialized_t;
/** @brief Construct an EtherAddress equal to 00-00-00-00-00-00. */
inline EtherAddress() {
_data[0] = _data[1] = _data[2] = 0;
}
/** @brief Construct an EtherAddress from data.
* @param data the address data, in network byte order
*
* The bytes data[0]...data[5] are used to construct the address. */
explicit inline EtherAddress(const unsigned char *data) {
memcpy(_data, data, 6);
}
/** @brief Construct an uninitialized EtherAddress. */
inline EtherAddress(const uninitialized_type &unused) {
(void) unused;
}
/** @brief Return the broadcast EtherAddress, FF-FF-FF-FF-FF-FF. */
static EtherAddress make_broadcast() {
return EtherAddress(0xFFFF);
}
static inline EtherAddress broadcast() CLICK_DEPRECATED;
typedef bool (EtherAddress::*unspecified_bool_type)() const;
/** @brief Return true iff the address is not 00-00-00-00-00-00. */
inline operator unspecified_bool_type() const {
return _data[0] || _data[1] || _data[2] ? &EtherAddress::is_group : 0;
}
/** @brief Return true iff this address is a group address.
*
* Group addresses have the low-order bit of the first byte set to 1, as
* in 01-00-00-00-00-00 or 03-00-00-02-04-09. */
inline bool is_group() const {
return data()[0] & 1;
}
/** @brief Return true iff this address is a "local" address.
*
* Local addresses have the next-to-lowest-order bit of the first byte set
* to 1. */
inline bool is_local() const {
return data()[0] & 2;
}
/** @brief Return true iff this address is the broadcast address.
*
* The Ethernet broadcast address is FF-FF-FF-FF-FF-FF. */
inline bool is_broadcast() const {
return _data[0] + _data[1] + _data[2] == 0x2FFFD;
}
/** @brief Return true if @a data points to a broadcast address. */
static inline bool is_broadcast(const unsigned char *data) {
#if HAVE_INDIFFERENT_ALIGNMENT
return reinterpret_cast<const EtherAddress *>(data)->is_broadcast();
#else
return data[0] + data[1] + data[2] + data[3] + data[4] + data[5] == 0x5FA;
#endif
}
/** @brief Return a pointer to the address data. */
inline unsigned char *data() {
return reinterpret_cast<unsigned char *>(_data);
}
/** @overload */
inline const unsigned char *data() const {
return reinterpret_cast<const unsigned char *>(_data);
}
/** @brief Return a pointer to the address data, as an array of
* uint16_ts. */
inline const uint16_t *sdata() const {
return _data;
}
/** @brief Hash function. */
inline size_t hashcode() const {
return (_data[2] | ((size_t) _data[1] << 16))
^ ((size_t) _data[0] << 9);
}
// bool operator==(EtherAddress, EtherAddress);
// bool operator!=(EtherAddress, EtherAddress);
/** @brief Unparse this address into a dash-separated hex String.
*
* Examples include "00-00-00-00-00-00" and "00-05-4E-50-3C-1A".
*
* @note The IEEE standard for printing Ethernet addresses uses dashes as
* separators, not colons. Use unparse_colon() to unparse into the
* nonstandard colon-separated form. */
inline String unparse() const {
return unparse_dash();
}
/** @brief Unparse this address into a colon-separated hex String.
*
* Examples include "00:00:00:00:00:00" and "00:05:4E:50:3C:1A".
*
* @note Use unparse() to create the IEEE standard dash-separated form. */
String unparse_colon() const;
/** @brief Unparse this address into a dash-separated hex String.
*
* Examples include "00-00-00-00-00-00" and "00-05-4E-50-3C-1A".
*
* @note This is the IEEE standard for printing Ethernet addresses.
* @sa unparse_colon */
String unparse_dash() const;
/** @brief Unparse this address into a dash-separated hex String.
* @deprecated The unparse() function should be preferred to s().
* @sa unparse */
inline String s() const CLICK_DEPRECATED;
/** @brief Unparse this address into a dash-separated hex String.
* @deprecated The unparse() function should be preferred to this cast.
* @sa unparse */
inline operator String() const CLICK_DEPRECATED;
typedef const EtherAddress &parameter_type;
private:
uint16_t _data[3];
EtherAddress(uint16_t m) {
_data[0] = _data[1] = _data[2] = m;
}
} CLICK_SIZE_PACKED_ATTRIBUTE;
inline EtherAddress EtherAddress::broadcast() {
return make_broadcast();
}
inline
EtherAddress::operator String() const
{
return unparse();
}
inline String
EtherAddress::s() const
{
return unparse();
}
/** @relates EtherAddress
@brief Compares two EtherAddress objects for equality. */
inline bool
operator==(const EtherAddress &a, const EtherAddress &b)
{
return (a.sdata()[0] == b.sdata()[0]
&& a.sdata()[1] == b.sdata()[1]
&& a.sdata()[2] == b.sdata()[2]);
}
/** @relates EtherAddress
@brief Compares two EtherAddress objects for inequality. */
inline bool
operator!=(const EtherAddress &a, const EtherAddress &b)
{
return !(a == b);
}
class StringAccum;
StringAccum &operator<<(StringAccum &, const EtherAddress &);
class ArgContext;
class Args;
extern const ArgContext blank_args;
/** @class EtherAddressArg
@brief Parser class for Ethernet addresses.
This is the default parser for objects of EtherAddress type. For 6-byte
arrays like "click_ether::ether_shost" and "click_ether::ether_dhost", you
must pass an EtherAddressArg() explicitly:
@code
struct click_ether ethh;
... Args(...) ...
.read_mp("SRC", EtherAddressArg(), ethh.ether_shost)
...
@endcode */
class EtherAddressArg { public:
typedef void enable_direct_parse;
EtherAddressArg(int flags = 0) : flags_(flags) {}
inline bool parse(const String& str, EtherAddress& value, const ArgContext& args = blank_args) {
return parse(str, value, args, flags_);
}
inline bool parse(const String& str, unsigned char* value, const ArgContext& args = blank_args) {
return parse(str, *reinterpret_cast<EtherAddress *>(value), args);
}
inline bool direct_parse(const String& str, EtherAddress& value, Args& args) {
return direct_parse(str, value, args, flags_);
}
inline bool direct_parse(const String& str, unsigned char* value, Args& args) {
return direct_parse(str, *reinterpret_cast<EtherAddress *>(value), args);
}
private:
int flags_;
static bool parse(const String& str, EtherAddress& value, const ArgContext& args, int flags);
static bool direct_parse(const String& str, EtherAddress& value, Args& args, int flags);
};
template<> struct DefaultArg<EtherAddress> : public EtherAddressArg {};
template<> struct has_trivial_copy<EtherAddress> : public true_type {};
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,521 @@
#ifndef CLICK_EWMA_HH
#define CLICK_EWMA_HH
#include <click/glue.hh>
#include <click/confparse.hh>
CLICK_DECLS
/** @file <click/ewma.hh>
* @brief Click's classes for supporting exponentially weighted moving
* averages.
*/
/** @class DirectEWMAX include/click/ewma.hh <click/ewma.hh>
* @brief An exponentially weighted moving average.
*
* The DirectEWMAX template class represents a simple exponentially weighted
* moving average. The average starts out with value 0. The update()
* function adds a new observation to the average.
*
* The template parameter P defines three EWMA parameters: value type,
* stability shift, and scale factor.
*
* The value type is simply the unsigned integral type used to store the
* average. It is also the type of each observation. <code>unsigned</code>
* and <code>uint64_t</code> are examples.
*
* The stability shift specifies alpha, the stability parameter. Concretely,
* alpha = 1. / (2 ** stability_shift). Thus, a stability shift of 4
* corresponds to an alpha of 1/16.
*
* The scaling factor specifies how many bits of fraction are kept per
* observation. Fraction bits are necessary to account for small differences
* between observations. For example, consider a EWMA with value 0, alpha
* 1/16, and 0 bits of fraction. Assume the EWMA begins to observe a stream
* of observations equal to 1. Despite these observations, the EWMA's value
* will never change from 0, since the 1/16 alpha factor rounds the new
* observations down to 0. At least 4 bits of fraction are required to
* account for this difference. There is a tradeoff: the more bits of
* fraction, the more precise the EWMA, but the less bits available to
* account for large values.
*
* These EWMA parameters are defined by five of P's members, two typedefs and
* three possibly static member functions.
*
* <dl>
* <dt><strong>P::value_type</strong></dt>
* <dd>The EWMA's value type. Example: <code>unsigned</code>.</dd>
*
* <dt><strong>P::signed_value_type</strong></dt>
* <dd>The signed version of <code>P::value_type</code>. Used internally.
* Example: <code>int</code>.</dd>
*
* <dt><strong>unsigned P::stability_shift()</strong></dt>
* <dd>This function should return this EWMA's stability shift
* (see above).</dd>
*
* <dt><strong>unsigned P::scale()</strong></dt>
* <dd>This function should return this EWMA's scaling factor
* (see above).</dd>
*
* <dt><strong>unsigned P::compensation()</strong></dt>
* <dd>This function should return this EWMA's stability compensation,
* which normally equals 1 @<@< (stability_shift - 1).</dd>
* </dl>
*
* Since DirectEWMAX inherits from an object of type P, these members are
* also directly available to callers.
*
* The FixedEWMAXParameters and StabilityEWMAXParameters types are good
* template arguments for DirectEWMAX.
*
* @sa RateEWMAX
*/
template <typename P>
class DirectEWMAX : public P { public:
typedef typename P::value_type value_type;
/** @brief Construct a EWMA with initial average 0. */
DirectEWMAX()
: _avg(0) {
}
/** @brief Construct a EWMA with initial scaled average @a scaled_value. */
DirectEWMAX(value_type scaled_value)
: _avg(scaled_value) {
}
/** @brief Return the current scaled moving average.
* @note The returned value has scale() bits of fraction. */
value_type scaled_average() const {
return _avg;
}
/** @brief Return the current moving average, rounded up.
* @note The returned value is unscaled (has zero bits of fraction). */
value_type unscaled_average() const {
return (_avg + (P::scaled_one() >> 1)) >> P::scale();
}
/** @brief Reset the EWMA to value 0. */
void clear() {
_avg = 0;
}
/** @brief Assign the EWMA to scaled average @a scaled_value. */
inline void assign(value_type scaled_value) {
_avg = scaled_value;
}
/** @brief Update the moving average with a new observation.
* @param x the observation (unscaled) */
inline void update(value_type x);
/** @brief Update the moving average with @a n identical observations.
* @param x the observation (unscaled)
* @param n number of observations
* @note This may be faster than calling update(@a x) @a n
* times. */
void update_n(value_type x, unsigned n);
/** @brief Unparse the current average into a String.
* @note The returned value is unscaled, but may contain a fractional
* part. */
String unparse() const;
/** @brief Update the moving average with a new observation (deprecated).
* @param x the observation (unscaled)
* @deprecated Use update() instead. */
inline void update_with(value_type x) CLICK_DEPRECATED;
private:
value_type _avg;
};
template <typename P>
inline void
DirectEWMAX<P>::update(value_type x)
{
value_type x_scaled = (x << P::scale()) + P::compensation();
unsigned stability = P::stability_shift();
#if HAVE_ARITHMETIC_RIGHT_SHIFT
_avg += static_cast<typename P::signed_value_type>(x_scaled - _avg) >> stability;
#else
if (x_scaled < _avg)
_avg -= (_avg - x_scaled) >> stability;
else
_avg += (x_scaled - _avg) >> stability;
#endif
}
template <typename P>
void
DirectEWMAX<P>::update_n(value_type x, unsigned n)
{
// XXX use table lookup
value_type x_scaled = x << P::scale();
if (n >= 100)
_avg = x_scaled;
else {
x_scaled += P::compensation();
unsigned stability = P::stability_shift();
#if HAVE_ARITHMETIC_RIGHT_SHIFT
for (; n > 0; n--)
_avg += static_cast<typename P::signed_value_type>(x_scaled - _avg) >> stability;
#else
if (x_scaled < _avg)
for (; n > 0; n--)
_avg -= (_avg - x_scaled) >> stability;
else
for (; n > 0; n--)
_avg += (x_scaled - _avg) >> stability;
#endif
}
}
template <typename P>
inline String
DirectEWMAX<P>::unparse() const
{
return cp_unparse_real2(scaled_average(), P::scale());
}
template <typename P>
inline void
DirectEWMAX<P>::update_with(value_type x)
{
update(x);
}
/** @class FixedEWMAXParameters include/click/ewma.hh <click/ewma.hh>
* @brief Parameters for a EWMA with constant scaling factor and stability
* shift.
*
* The FixedEWMAXParameters template class is used as a template argument to
* DirectEWMAX. It defines a EWMA with fixed constant scaling factor and
* stability shift. FixedEWMAXParameters's first template argument is the
* EWMA's stability shift, its second template argument is the EWMA's scaling
* factor, its third template argument is the EWMA's value type, and the
* fourth template argument is the EWMA's signed value type.
*
* Example 1: <code>DirectEWMAX@<FixedEWMAXParameters@<4, 10, unsigned, int@>
* @></code> defines a EWMA with alpha 1/16 (stability shift 4), scaling
* factor 10, and value type unsigned. (These are the default parameters
* available in the DirectEWMA typedef.)
*
* Example 2: <code>DirectEWMAX@<FixedEWMAXParameters@<3, 10, uint64_t,
* int64_t@> @></code> defines a EWMA with alpha 1/8 (stability shift 3),
* scaling factor 10, and value type uint64_t.
*/
template <unsigned STABILITY, unsigned SCALE, typename T = unsigned, typename U = int>
class FixedEWMAXParameters { public:
typedef T value_type;
typedef U signed_value_type;
/** @brief Return this EWMA's stability shift.
* @return the 1st template parameter */
static unsigned stability_shift() {
return STABILITY;
}
/** @brief Return this EWMA's scaling factor (bits of fraction).
* @return the 2nd template parameter */
static unsigned scale() {
static_assert(SCALE < sizeof(T) * 8, "SCALE too big for EWMA type.");
return SCALE;
}
/** @brief Return this EWMA's scaled value for one. */
static value_type scaled_one() {
return (value_type) 1 << SCALE;
}
/** @brief Return this EWMA's compensation.
* @return 1 << (stability_shift() - 1) */
static unsigned compensation() {
return 1 << (STABILITY - 1);
}
};
/** @brief A DirectEWMAX with stability shift 4 (alpha 1/16), scaling factor
* 10 (10 bits of fraction), and underlying type <code>unsigned</code>. */
typedef DirectEWMAX<FixedEWMAXParameters<4, 10> > DirectEWMA;
/** @brief A DirectEWMAX with stability shift 3 (alpha 1/8), scaling factor
* 10 (10 bits of fraction), and underlying type <code>unsigned</code>. */
typedef DirectEWMAX<FixedEWMAXParameters<3, 10> > FastDirectEWMA;
/** @class StabilityEWMAXParameters include/click/ewma.hh <click/ewma.hh>
* @brief Parameters for a EWMA with constant scaling factor
* and user-settable alpha.
*
* The StabilityEWMAXParameters template class is used as a template argument
* to DirectEWMAX. It defines a EWMA with fixed constant scaling factor.
* StabilityEWMAXParameters's first template argument is the EWMA's scaling
* factor, its second template argument is the EWMA's value type, and the
* third template argument is the EWMA's signed value type.
*
* Example: <code>DirectEWMAX@<StabilityEWMAXParameters@<10, unsigned, int@>
* @></code> defines a EWMA with user-settable alpha (stability shift)
* initially equal to 1/16, scaling factor 10, and value type unsigned.
*
* A <code>DirectEWMAX@<StabilityEWMAXParameters@<...@> @></code> object has
* stability_shift() and set_stability_shift() methods.
*/
template <unsigned SCALE, typename T = unsigned, typename U = int>
class StabilityEWMAXParameters { public:
typedef T value_type;
typedef U signed_value_type;
/** @brief Construct a StabilityEWMAXParameters with initial alpha 1/16. */
StabilityEWMAXParameters()
: _stability(4) {
}
/** @brief Return the current stability shift.
*
* The current alpha equals 1. / (2 ** stability_shift()). */
unsigned stability_shift() const {
return _stability;
}
/** @brief Set the current stability shift.
* @param stability_shift new value */
void set_stability_shift(unsigned stability_shift) {
_stability = stability_shift;
}
/** @brief Return this EWMA's scaling factor (bits of fraction).
* @return the 1st template parameter */
static unsigned scale() {
return SCALE;
}
/** @brief Return this EWMA's scaled value for one. */
static value_type scaled_one() {
return (value_type) 1 << SCALE;
}
/** @brief Return this EWMA's compensation.
* @return 1 << (stability_shift() - 1) */
unsigned compensation() const {
return 1 << (stability_shift() - 1);
}
private:
unsigned _stability;
};
/** @class RateEWMAX include/click/ewma.hh <click/ewma.hh>
* @brief An exponentially weighted moving average used to measure a rate.
*
* The RateEWMAX template class represents an exponentially weighted moving
* average that measures a <em>rate</em>: a count of events per unit time.
* The average starts out with value 0.
*
* RateEWMAX adds to DirectEWMAX a concept of epochs, which are periods of
* time. A RateEWMAX object collects samples over the current epoch. When
* the epoch closes, the collected sample count is used to update the moving
* average. Thus, the moving average is measured in samples per epoch. The
* rate() and unparse_rate() member functions return the rate in samples per
* <em>second</em>, rather than per epoch. These functions use the epoch
* frequency to translate between epochs and seconds.
*
* Note that it often makes sense to call update() before calling
* scaled_average(), rate(), or unparse_rate(), in case an epoch or two has
* passed and the average should take account of passing time.
*
* The template parameter P defines the EWMA parameters required by
* DirectEWMAX, and three others: a rate count, an epoch measurement, and an
* epoch frequency.
*
* The rate count is the number of rates measured per object. Usually it is
* 1.
*
* The epoch measurement is a function that returns the current epoch as an
* unsigned number. Epochs should increase monotonically.
*
* The epoch frequency is the number of epochs per second, and is only used
* by rate() and unparse_rate().
*
* These are defined by:
*
* <dl>
* <dt><strong>P::rate_count</strong></dt>
* <dd>The rate count, as a static constant (for example, defined by an
* enum).</dd>
*
* <dt><strong>unsigned P::epoch()</strong></dt>
* <dd>This function returns the current epoch number.</dd>
*
* <dt><strong>unsigned P::epoch_frequency()</strong></dt>
* <dd>This function returns the number of epochs per second.</dd>
* </dl>
*
* Since RateEWMAX inherits from an object of type P, these members are
* also directly available to callers.
*
* The RateEWMAXParameters type is a good template argument for RateEWMAX.
*
* @sa DirectEWMAX
*/
template <typename P>
class RateEWMAX : public P { public:
typedef typename P::value_type value_type;
typedef typename P::signed_value_type signed_value_type;
/** @brief Create a rate EWMA with initial value(s) 0. */
RateEWMAX() {
_current_epoch = P::epoch();
for (unsigned i = 0; i < P::rate_count; i++)
_current[i] = 0;
}
/** @brief Return the current scaled moving average.
* @param ratenum rate index (0 <= ratenum < rate_count)
* @note The returned value has scale() bits of fraction.
* @note scaled_average() does not check the current epoch.
* If an epoch might have passed since the last update(), you
* should call update(0, @a ratenum) before calling this
* function. */
signed_value_type scaled_average(unsigned ratenum = 0) const {
// note: return type must be signed!
return _avg[ratenum].scaled_average();
}
/** @brief Returns one of the average's scaling factors (bits of
* fraction). */
unsigned scale(unsigned ratenum = 0) const {
return _avg[ratenum].scale();
}
/** @brief Return the current rate in samples per second.
* @param ratenum rate index (0 <= ratenum < rate_count)
* @note The returned value is unscaled.
* @note rate() does not check the current epoch.
* If an epoch might have passed since the last update(), you
* should call update(0, @a ratenum) before calling this
* function. */
inline int rate(unsigned ratenum = 0) const;
/** @brief Update the sample count for the current epoch.
* @param delta increment for current epoch sample count
* @param ratenum rate index (0 <= ratenum < rate_count)
* @note If the epoch has changed since the last update(),
* this function applies the last epoch's sample count (if any)
* to the relevant moving average, accounts for any passage of
* time (in case one or more epochs have passed with no samples),
* and clears the sample count for the new epoch. */
inline void update(signed_value_type delta, unsigned ratenum = 0);
/** @brief Unparse the current average into a String.
* @param ratenum rate index (0 <= ratenum < rate_count)
* @note The returned value is unscaled, but may contain a fractional
* part.
* @note unparse_rate() does not check the current epoch.
* If an epoch might have passed since the last update(), you
* should call update(0, @a ratenum) before calling this
* function. */
String unparse_rate(unsigned ratenum = 0) const;
private:
unsigned _current_epoch;
value_type _current[P::rate_count];
DirectEWMAX<P> _avg[P::rate_count];
inline void update_time(unsigned now);
};
/** @class RateEWMAXParameters include/click/ewma.hh <click/ewma.hh>
* @brief Parameters for a RateEWMA with constant scaling factor
* and alpha, one rate count, and epochs of jiffies.
*
* The RateEWMAXParameters template class is used as a template argument
* to RateEWMAX. It defines a EWMA with fixed constant scaling factor and
* alpha and one rate count. The EWMA uses jiffies as epochs. Template
* parameters are as for DirectEWMAXParameters.
*
* Example: <code>RateEWMAX@<RateEWMAXParameters@<4, 10, unsigned, int@>
* @></code> defines a rate EWMA with user-settable alpha (stability shift)
* initially equal to 1/16, scaling factor 10, and value type unsigned.
*/
template <unsigned STABILITY, unsigned SCALE, typename T = unsigned, typename U = int>
class RateEWMAXParameters : public FixedEWMAXParameters<STABILITY, SCALE, T, U> { public:
enum {
rate_count = 1
};
/** @brief Return the current epoch number.
* @note RateEWMAXParameters measures epochs in jiffies. */
static unsigned epoch() {
return click_jiffies();
}
/** @brief Return the number of epochs (jiffies) per second. */
static unsigned epoch_frequency() {
return CLICK_HZ;
}
};
/** @brief A RateEWMAX with stability shift 4 (alpha 1/16), scaling factor 10
* (10 bits of fraction), one rate, and underlying type <code>unsigned</code>
* that measures epochs in jiffies. */
typedef RateEWMAX<RateEWMAXParameters<4, 10> > RateEWMA;
template <typename P>
inline void
RateEWMAX<P>::update_time(unsigned now)
{
unsigned jj = _current_epoch;
if (now != jj) {
for (unsigned i = 0; i < P::rate_count; i++) {
// adjust the average rate using the last measured packets
_avg[i].update(_current[i]);
// adjust for time w/ no packets
if (jj + 1 != now)
_avg[i].update_n(0, now - jj - 1);
_current[i] = 0;
}
_current_epoch = now;
}
}
template <typename P>
inline void
RateEWMAX<P>::update(signed_value_type delta, unsigned ratenum)
{
update_time(P::epoch());
_current[ratenum] += delta;
}
template <typename P>
inline int
RateEWMAX<P>::rate(unsigned ratenum) const
{
return (scaled_average(ratenum) * P::epoch_frequency()) >> _avg[ratenum].scale();
}
template <typename P>
inline String
RateEWMAX<P>::unparse_rate(unsigned ratenum) const
{
return cp_unparse_real2(scaled_average(ratenum) * P::epoch_frequency(), _avg[ratenum].scale());
}
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,24 @@
#ifndef CLICK_FIXCONFIG_H
#define CLICK_FIXCONFIG_H
#if CLICK_LINUXMODULE && __cplusplus
#include <click/type_traits.hh>
#define __builtin_types_compatible_p(a, b) \
(types_compatible<typeof(a), typeof(b)>::value)
#endif
#if CLICK_LINUXMODULE && HAVE_LINUX_ASM_ALTERNATIVE_H
// The .smp_locks section and C++-style weak linkage interact badly.
# if CONFIG_SMP && (defined(__i386__) || defined(__x86_64__))
# include <click/cxxprotect.h>
CLICK_CXX_PROTECT
# include <asm/alternative.h>
# undef LOCK_PREFIX
# define LOCK_PREFIX "lock ; "
CLICK_CXX_UNPROTECT
# include <click/cxxunprotect.h>
# endif
#endif
#endif

View File

@ -0,0 +1,96 @@
// -*- related-file-name: "../../lib/fromfile.cc"; c-basic-offset: 4 -*-
#ifndef CLICK_FROMFILE_HH
#define CLICK_FROMFILE_HH
#include <click/string.hh>
#include <click/vector.hh>
#include <stdio.h>
CLICK_DECLS
class ErrorHandler;
class Element;
class Packet;
class WritablePacket;
class FromFile { public:
FromFile();
~FromFile() { cleanup(); }
const String &filename() const { return _filename; }
String &filename() { return _filename; }
bool initialized() const { return _fd != -1; }
void set_landmark_pattern(const String &lp) { _landmark_pattern = lp; }
String landmark(const String &landmark_pattern) const;
String landmark() const { return landmark(_landmark_pattern); }
String print_filename() const;
int lineno() const { return _lineno; }
void set_lineno(int lineno) { _lineno = lineno; }
off_t file_pos() const { return _file_offset + _pos; }
int configure_keywords(Vector<String>& conf, Element* e, ErrorHandler* errh);
int set_data(const String& data, ErrorHandler* errh);
int initialize(ErrorHandler* errh, bool allow_nonexistent = false);
void add_handlers(Element* e, bool filepos_writable = false) const;
void cleanup();
void take_state(FromFile &, ErrorHandler *);
int seek(off_t want, ErrorHandler *);
int read(void*, uint32_t, ErrorHandler * = 0);
const uint8_t* get_unaligned(size_t, void*, ErrorHandler* = 0);
const uint8_t* get_aligned(size_t, void*, ErrorHandler* = 0);
String get_string(size_t, ErrorHandler* = 0);
Packet* get_packet(size_t, uint32_t sec, uint32_t subsec, ErrorHandler *);
Packet* get_packet_from_data(const void *buf, size_t buf_size, size_t full_size, uint32_t sec, uint32_t subsec, ErrorHandler *);
void shift_pos(int delta) { _pos += delta; }
int read_line(String &str, ErrorHandler *errh, bool temporary = false);
int peek_line(String &str, ErrorHandler *errh, bool temporary = false);
int error(ErrorHandler *, const char *format, ...) const;
int warning(ErrorHandler *, const char *format, ...) const;
private:
enum { BUFFER_SIZE = 32768 };
int _fd;
const uint8_t *_buffer;
uint32_t _pos;
uint32_t _len;
WritablePacket *_data_packet;
#ifdef ALLOW_MMAP
bool _mmap;
#endif
#ifdef ALLOW_MMAP
enum { WANT_MMAP_UNIT = 4194304 }; // 4 MB
size_t _mmap_unit;
off_t _mmap_off;
#endif
String _filename;
FILE *_pipe;
off_t _file_offset;
String _landmark_pattern;
int _lineno;
#ifdef ALLOW_MMAP
int read_buffer_mmap(ErrorHandler *);
#endif
int read_buffer(ErrorHandler *);
bool read_packet(ErrorHandler *);
int skip_ahead(ErrorHandler *);
static String filename_handler(Element *, void *);
static String filesize_handler(Element *, void *);
static String filepos_handler(Element *, void *);
static int filepos_write_handler(const String&, Element*, void*, ErrorHandler*);
};
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,240 @@
// -*- c-basic-offset: 4; related-file-name: "../../lib/gaprate.cc" -*-
#ifndef CLICK_GAPRATE_HH
#define CLICK_GAPRATE_HH
#include <click/timestamp.hh>
CLICK_DECLS
class ErrorHandler;
/** @file <click/gaprate.hh>
* @brief A Click helper class for implementing a uniform rate.
*/
/** @class GapRate include/click/gaprate.hh <click/gaprate.hh>
* @brief A helper class for implementing a uniform rate.
*
* The GapRate class helps its user implement a process with a uniform rate:
* a process in which one user event happens every T seconds. GapRate is
* designed to efficiently model high rates. (Contrast this with Timer,
* which can serve a similar function at low rates.)
*
* GapRate is not a great choice for limiting the rates of external
* processes. See TokenBucketX, a token bucket rate limiter.
*
* GapRate models an underlying "true" rated process with the correct rate.
* It also keeps a counter, maintained by its user via the update() method,
* that measures the progress of the user's rated process. The
* needs_update() method compares this counter with its expected value, which
* is determined by the true rated process. If the user's rated process is
* running behind, then needs_update() returns true; the user should trigger
* an event and call the update() method. If the user's rated process is
* just right or is running faster than the true process, then needs_update()
* returns false; the user should <em>not</em> trigger an event.
*
* Creating a non-bursty rate can be expensive and difficult. GapRate
* attempts to create a non-bursty rate using timestamps and some interesting
* microsecond-based arithmetic. External factors can cause scheduling
* hiccups where GapRate is not called as much as expected. GapRate
* compensates for hiccups: the user's rated process may fall up to a full
* second behind the true rated process, then catch up in a burst. More than
* one second's worth of lag is ignored.
*
* The maximum rate GapRate can implement is MAX_RATE events per second.
*
* @sa TokenBucketX, Timer
*/
class GapRate { public:
/** @brief Construct a GapRate object with initial rate 0. */
inline GapRate();
/** @brief Construct a GapRate object with initial rate @a r.
* @param r initial rate (events per second) */
inline GapRate(unsigned r);
/** @brief Return the current rate. */
inline unsigned rate() const;
/** @brief Set the current rate to @a r.
* @param r desired rate (events per second)
*
* Rates larger than MAX_RATE are reduced to MAX_RATE. Also performs the
* equivalent of a reset() to flush old state. */
inline void set_rate(unsigned r);
/** @brief Set the current rate to @a r.
* @param r desired rate (events per second)
* @param errh error handler
*
* Acts like set_rate(@a r), except that an warning is reported to @a errh
* if @a r is larger than MAX_RATE. */
void set_rate(unsigned r, ErrorHandler *errh);
/** @brief Returns whether the user's rate is behind the true rate.
* @param ts current timestamp
*
* Returns true iff the user's rate is currently behind the true rate,
* meaning the user should cause an event and call update(). */
inline bool need_update(const Timestamp &ts);
/** @brief Returns a time when the user's rate will be behind the true rate.
* @pre need_update() has been called at least once.
* @return If the rate is 0, or need_update() has not been called,
* returns Timestamp(). If the user's rate is already behind the true
* rate, returns a time no greater than the argument passed to the last
* need_update(). Otherwise, returns a time in the future when
* need_update() will return true.
*/
inline Timestamp expiry() const;
/** @brief Increment the user event counter.
*
* Call this function when causing a user event. */
inline void update();
/** @brief Increment the user event counter by @a delta.
* @param delta number of user events
*
* @note This may be faster than calling update() @a delta times.
* Furthermore, @a delta can be negative. */
inline void update_with(int delta);
/** @brief Resets the true rate counter.
*
* This function flushes any old information about the true rate counter
* and its relationship to the user's rate counter. */
inline void reset();
enum { UGAP_SHIFT = 12 };
enum { MAX_RATE = 1000000U << UGAP_SHIFT };
private:
unsigned _ugap; // (1000000 << UGAP_SHIFT) / _rate
int _sec_count; // number of updates this second so far
Timestamp::seconds_type _tv_sec; // current second
unsigned _rate; // desired rate
#if DEBUG_GAPRATE
Timestamp _last;
#endif
inline void initialize_rate(unsigned rate);
};
/** @brief Reset the underlying rated process. */
inline void
GapRate::reset()
{
_tv_sec = -1;
#if DEBUG_GAPRATE
_last.set_sec(0);
#endif
}
inline void
GapRate::initialize_rate(unsigned r)
{
_rate = r;
_ugap = (r == 0 ? MAX_RATE + 1 : MAX_RATE / r);
#if DEBUG_GAPRATE
click_chatter("ugap: %u", _ugap);
#endif
}
inline void
GapRate::set_rate(unsigned r)
{
if (r > MAX_RATE)
r = MAX_RATE;
if (_rate != r) {
initialize_rate(r);
if (_tv_sec >= 0 && r != 0) {
Timestamp now = Timestamp::now();
_sec_count = (now.usec() << UGAP_SHIFT) / _ugap;
}
}
}
inline
GapRate::GapRate()
{
initialize_rate(0);
reset();
}
inline
GapRate::GapRate(unsigned r)
: _rate(0)
{
initialize_rate(r);
reset();
}
inline unsigned
GapRate::rate() const
{
return _rate;
}
inline bool
GapRate::need_update(const Timestamp &now)
{
// this is an approximation of:
// unsigned need = (unsigned) ((now.usec() / 1000000.0) * _rate)
unsigned need = (now.usec() << UGAP_SHIFT) / _ugap;
if (_tv_sec < 0) {
// 27.Feb.2005: often OK to send a packet after reset unless rate is
// 0 -- requested by Bart Braem
// check include/click/gaprate.hh (1.2)
_tv_sec = now.sec();
_sec_count = need + ((now.usec() << UGAP_SHIFT) - (need * _ugap) > _ugap / 2);
} else if (now.sec() > _tv_sec) {
_tv_sec = now.sec();
if (_sec_count > 0)
_sec_count -= _rate;
}
#if DEBUG_GAPRATE
click_chatter("%p{timestamp} -> %u @ %u [%d]", &now, need, _sec_count, (int)need >= _sec_count);
#endif
return ((int)need >= _sec_count);
}
inline void
GapRate::update()
{
_sec_count++;
}
inline void
GapRate::update_with(int delta)
{
_sec_count += delta;
}
inline Timestamp
GapRate::expiry() const
{
if (_tv_sec < 0 || _rate == 0)
return Timestamp();
else if (_sec_count < 0)
return Timestamp(_tv_sec, 0);
else {
Timestamp::seconds_type sec = _tv_sec;
int count = _sec_count;
if ((unsigned) count >= _rate) {
sec += count / _rate;
count = count % _rate;
}
// uint32_t usec = (int) (count * 1000000.0 / _rate)
uint32_t usec = (count * _ugap) >> UGAP_SHIFT;
return Timestamp::make_usec(sec, usec);
}
}
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,702 @@
// -*- c-basic-offset: 4; related-file-name: "../../lib/glue.cc" -*-
#ifndef CLICK_GLUE_HH
#define CLICK_GLUE_HH
// Removes many common #include <header>s and abstracts differences between
// kernel and user space, and between operating systems.
// HEADERS
#if CLICK_LINUXMODULE
# define _LOOSE_KERNEL_NAMES 1 /* define ino_t, off_t, etc. */
# undef __KERNEL_STRICT_NAMES
# ifndef __OPTIMIZE__
# define __OPTIMIZE__ 1 /* get ntohl() macros. otherwise undefined. */
# endif
# include <click/cxxprotect.h>
CLICK_CXX_PROTECT
# ifdef WANT_MOD_USE_COUNT
# define __NO_VERSION__
# include <linux/module.h>
# define HAVE_MOD_USE_COUNT 1
# endif
# include <linux/kernel.h>
# include <linux/string.h>
# include <linux/skbuff.h>
# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
# include <linux/malloc.h>
# include <linux/vmalloc.h>
# include <linux/interrupt.h>
# else
# include <linux/hardirq.h>
# endif
# include <linux/ctype.h>
# include <linux/time.h>
# include <linux/errno.h>
CLICK_CXX_UNPROTECT
# include <click/cxxunprotect.h>
#elif CLICK_BSDMODULE
# include <click/cxxprotect.h>
CLICK_CXX_PROTECT
# include <sys/ctype.h>
# include <sys/systm.h>
# include <sys/time.h>
# include <sys/param.h>
# include <sys/kernel.h>
# include <sys/mbuf.h>
# include <sys/malloc.h>
# include <sys/libkern.h>
# include <sys/proc.h>
# include <sys/sysproto.h>
# include <sys/limits.h>
# include <sys/module.h> /* XXX: for packages */
CLICK_CXX_UNPROTECT
# include <click/cxxunprotect.h>
#elif CLICK_MINIOS
# include <click/cxxprotect.h>
CLICK_CXX_PROTECT
# include <stdio.h>
# include <stdlib.h>
# include <stddef.h>
# include <stdint.h>
# include <string.h>
# include <ctype.h>
# include <errno.h>
# include <limits.h>
# include <time.h>
# include <sys/socket.h>
# include <netinet/in.h>
# include <sys/time.h>
CLICK_CXX_UNPROTECT
# include <click/cxxunprotect.h>
#else /* CLICK_USERLEVEL */
# include <stdio.h>
# include <stdlib.h>
# include <stddef.h>
# include <stdint.h>
# include <string.h>
# include <ctype.h>
# include <errno.h>
# include <limits.h>
# include <time.h>
# include <sys/socket.h>
# include <netinet/in.h>
# include <sys/time.h>
# if CLICK_NS
extern "C" int simclick_gettimeofday(struct timeval *);
# endif
# if HAVE_MULTITHREAD
# include <pthread.h>
# include <sched.h>
# endif
#endif
// DEBUGGING OUTPUT
extern "C" {
void click_chatter(const char *fmt, ...);
}
// DEBUG MALLOC
#if CLICK_DMALLOC && (CLICK_LINUXMODULE || CLICK_BSDMODULE || CLICK_MINIOS)
extern uint32_t click_dmalloc_where;
# define CLICK_DMALLOC_REG(s) do { const unsigned char *__str = reinterpret_cast<const unsigned char *>(s); click_dmalloc_where = (__str[0]<<24) | (__str[1]<<16) | (__str[2]<<8) | __str[3]; } while (0)
#else
# define CLICK_DMALLOC_REG(s)
#endif
// LALLOC
#if CLICK_LINUXMODULE
# define CLICK_LALLOC(size) (click_lalloc((size)))
# define CLICK_LFREE(p, size) (click_lfree((p), (size)))
extern "C" {
void *click_lalloc(size_t size);
void click_lfree(volatile void *p, size_t size);
}
#else
# define CLICK_LALLOC(size) ((void *)(new uint8_t[(size)]))
# define CLICK_LFREE(p, size) delete[] ((void) (size), (uint8_t *)(p))
#endif
// RANDOMNESS
CLICK_DECLS
/** @brief Return a number between 0 and CLICK_RAND_MAX, inclusive.
*
* CLICK_RAND_MAX is guaranteed to be at least 2^31 - 1. */
uint32_t click_random();
/** @brief Return a number between @a low and @a high, inclusive.
*
* Returns @a low if @a low >= @a high. */
uint32_t click_random(uint32_t low, uint32_t high);
/** @brief Set the click_random() seed to @a seed. */
void click_srandom(uint32_t seed);
/** @brief Set the click_random() seed using a source of true randomness,
* if available. */
void click_random_srandom();
#if CLICK_BSDMODULE
# define CLICK_RAND_MAX 0x7FFFFFFFU
#elif !CLICK_LINUXMODULE && RAND_MAX >= 0x7FFFFFFFU
# define CLICK_RAND_MAX RAND_MAX
#else
# define CLICK_RAND_MAX 0x7FFFFFFFU
extern uint32_t click_random_seed;
#endif
#if CLICK_NS
extern uint32_t click_random();
#else
inline uint32_t click_random() {
# if CLICK_BSDMODULE
return random();
# elif CLICK_LINUXMODULE
click_random_seed = click_random_seed * 69069L + 5;
return (click_random_seed ^ jiffies) & CLICK_RAND_MAX; // XXX jiffies??
#elif CLICK_MINIOS
return rand();
# elif HAVE_RANDOM && CLICK_RAND_MAX == RAND_MAX
// See also click_random() in ns/nsclick.cc
return random();
# else
return rand();
# endif
}
#endif
inline void click_srandom(uint32_t seed) {
#if CLICK_BSDMODULE
srandom(seed);
#elif CLICK_LINUXMODULE
click_random_seed = seed;
#elif CLICK_MINIOS
srand(seed);
#elif CLICK_NS
(void) seed; /* XXX */
#elif HAVE_RANDOM && CLICK_RAND_MAX == RAND_MAX
srandom(seed);
#else
srand(seed);
#endif
}
CLICK_ENDDECLS
// SORTING
/** @brief Sort array of elements according to @a compar.
* @param base pointer to array of elements
* @param n number of elements in @a param
* @param size size of an element
* @param compar comparison function
* @param user_data user data for comparison function
*
* Sorts an array of elements. The comparison function is called as "@a
* param(@i a, @i b, @a user_data)", where @i a and @i b are pointers into the
* array starting at @a base, and @a user_data is click_qsort's @a user_data
* parameter. The function should return an integer less than zero, equal to
* zero, or greater than zero depending on whether @i a compares less than @i
* b, equal to @i b, or greater than @i b, respectively. On return the
* elements in the @a param array have been reordered into strictly increasing
* order. The function always returns 0.
*
* Click_qsort() is not a stable sort.
*
* @warning click_qsort() shuffles elements by swapping memory, rather than by
* calling copy constructors or swap(). It is thus not safe for all types.
* In particular, objects like Bitvector that maintain pointers into their own
* representations are not safe to sort with click_qsort(). Conservatively,
* it is safe to sort fundamental data types (like int and pointers), plain
* old data types, and simple objects. It is also safe to sort String and
* StringAccum objects, and to sort Vector objects that contain objects
* that are safe to sort themselves.
*
* @note The implementation is based closely on "Engineering a Sort Function,"
* Jon L. Bentley and M. Douglas McIlroy, <em>Software---Practice &
* Experience</em>, 23(11), 1249-1265, Nov. 1993. It has been coded
* iteratively rather than recursively, and does no dynamic memory allocation,
* so it will not exhaust stack space in the kernel. */
int click_qsort(void *base, size_t n, size_t size,
int (*compar)(const void *a, const void *b, void *user_data),
void *user_data = 0);
/** @brief Sort array of elements according to @a compar.
* @param base pointer to array of elements
* @param n number of elements in @a param
* @param size size of an element
* @param compar comparison function
*
* @deprecated Prefer the variant where @a compar takes an extra void
* *user_data argument. This variant depends on a nonstandard function
* pointer cast. */
int click_qsort(void *base, size_t n, size_t size,
int (*compar)(const void *a, const void *b)) CLICK_DEPRECATED;
/** @brief Generic comparison function useful for click_qsort.
*
* Compares @a a and @a b using operator<(). */
template <typename T> int click_compare(const void *a, const void *b, void *)
{
const T *ta = static_cast<const T *>(a);
const T *tb = static_cast<const T *>(b);
return (*ta < *tb ? -1 : (*tb < *ta ? 1 : 0));
}
/** @brief Sort array of elements using operator<(). */
template <typename T> int click_qsort(T *base, size_t n)
{
return click_qsort(base, n, sizeof(T), (int (*)(const void *, const void *, void *)) &click_compare<T>);
}
// OTHER
#if CLICK_LINUXMODULE
extern "C" {
long strtol(const char *, char **, int);
inline unsigned long
strtoul(const char *nptr, char **endptr, int base)
{
return simple_strtoul(nptr, endptr, base);
}
# if __GNUC__ == 2 && __GNUC_MINOR__ == 96
int click_strcmp(const char *, const char *);
inline int
strcmp(const char *a, const char *b)
{
return click_strcmp(a, b);
}
# endif
}
#elif CLICK_BSDMODULE
/* Char-type glue */
# define _U 0x01 /* upper */
# define _L 0x02 /* lower */
# define _D 0x04 /* digit */
# define _C 0x08 /* cntrl */
# define _P 0x10 /* punct */
# define _S 0x20 /* white space (space/lf/tab) */
# define _X 0x40 /* hex digit */
# define _SP 0x80 /* hard space (0x20) */
extern unsigned char _ctype[];
# define __ismask(x) (_ctype[(int)(unsigned char)(x)])
# define isalnum(c) ((__ismask(c)&(_U|_L|_D)) != 0)
# define strchr(s, c) index(s, c)
# if __FreeBSD_version >= 700000 && __FreeBSD_version < 730000
/* memmove() appeared in the FreeBSD 7.3 kernel */
extern "C" void *memmove(void *dest, const void *src, size_t len);
# endif
typedef struct ifnet net_device;
#else /* not CLICK_LINUXMODULE || CLICK_BSDMODULE */
// provide a definition for net_device
typedef struct device net_device;
#endif /* CLICK_LINUXMODULE */
// COMPILE-TIME ASSERTION CHECKING
#if (!defined(__cplusplus) || !HAVE_CXX_STATIC_ASSERT) && !defined(static_assert)
# define static_assert(x, ...) switch ((int) (x)) case 0: case !!((int) (x)):
#endif
// PROCESSOR IDENTITIES
#if CLICK_LINUXMODULE
typedef uint32_t click_processor_t;
# define CLICK_CPU_MAX NR_CPUS
#elif CLICK_USERLEVEL && HAVE_MULTITHREAD
typedef pthread_t click_processor_t;
# define CLICK_CPU_MAX 256
#else
typedef int8_t click_processor_t;
# if HAVE_MULTITHREAD
# define CLICK_CPU_MAX 256
# else
# define CLICK_CPU_MAX 1
# endif
#endif
inline click_processor_t
click_get_processor()
{
#if CLICK_LINUXMODULE
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
return get_cpu();
# else
return current->processor;
# endif
#elif CLICK_USERLEVEL && HAVE_MULTITHREAD
return pthread_self();
#else
return 0;
#endif
}
inline void
click_put_processor()
{
#if CLICK_LINUXMODULE
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
# ifdef put_cpu_no_resched
put_cpu_no_resched();
# else
put_cpu();
# endif
# endif
#endif
}
#if CLICK_USERLEVEL && HAVE_MULTITHREAD && HAVE___THREAD_STORAGE_CLASS
extern __thread int click_current_thread_id;
#endif
#if CLICK_USERLEVEL
extern int click_nthreads;
#endif
inline click_processor_t
click_current_processor()
{
#if CLICK_LINUXMODULE
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
return smp_processor_id();
# else
return current->processor;
# endif
#elif CLICK_USERLEVEL && HAVE_MULTITHREAD
return pthread_self();
#else
return 0;
#endif
}
inline unsigned
click_current_cpu_id()
{
#if !HAVE_MULTITHREAD
return 0;
#elif CLICK_USERLEVEL
# if HAVE___THREAD_STORAGE_CLASS
return click_current_thread_id & 0xffff;
# else
return sched_getcpu();
# endif
#else
return click_current_processor();
#endif
}
/**
* Return an upper bound to click_current_cpu_id()
*/
inline unsigned
click_max_cpu_ids()
{
#if CLICK_LINUXMODULE
return NR_CPUS;
#elif CLICK_USERLEVEL && HAVE___THREAD_STORAGE_CLASS
return click_nthreads;
#else //XXX BSDMODULE?
return CLICK_CPU_MAX;
#endif
}
inline click_processor_t
click_invalid_processor()
{
#if CLICK_LINUXMODULE
return -1;
#elif CLICK_USERLEVEL && HAVE_MULTITHREAD
return 0;
#else
return -1;
#endif
}
// TIMEVALS AND JIFFIES
// click_jiffies_t is the type of click_jiffies() and must be unsigned.
// click_jiffies_difference_t is the signed version of click_jiffies_t.
// CLICK_JIFFIES_MONOTONIC is true if click_jiffies() never goes backwards.
#if CLICK_LINUXMODULE
# define click_gettimeofday(tvp) (do_gettimeofday(tvp))
typedef unsigned long click_jiffies_t;
typedef long click_jiffies_difference_t;
# define click_jiffies() (jiffies)
# define CLICK_JIFFIES_MONOTONIC 1
# define CLICK_HZ HZ
# define click_jiffies_less(a, b) ((click_jiffies_difference_t) ((a) - (b)) < 0)
# define HAS_LONG_CLICK_JIFFIES_T 1
#elif CLICK_BSDMODULE
# define click_gettimeofday(tvp) (getmicrotime(tvp))
typedef unsigned click_jiffies_t;
typedef int click_jiffies_difference_t;
# define click_jiffies() (ticks)
# define CLICK_HZ hz
# define click_jiffies_less(a, b) ((click_jiffies_difference_t) ((a) - (b)) < 0)
#else
CLICK_DECLS
void click_gettimeofday(timeval *tvp) CLICK_DEPRECATED;
typedef unsigned click_jiffies_t;
typedef int click_jiffies_difference_t;
click_jiffies_t click_jiffies();
# define click_jiffies_less(a, b) ((click_jiffies_difference_t) ((a) - (b)) < 0)
CLICK_ENDDECLS
# define CLICK_HZ 1000
#endif
#if SIZEOF_CLICK_JIFFIES_T != (HAS_LONG_CLICK_JIFFIES_T ? SIZEOF_LONG : SIZEOF_INT)
# error "SIZEOF_CLICK_JIFFIES_T declared incorrectly"
#endif
// TIMEVAL OPERATIONS
#ifndef timercmp
// Convenience macros for operations on timevals.
// NOTE: 'timercmp' does not work for >= or <=.
# define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec)
# define timerclear(tvp) ((tvp)->tv_sec = (tvp)->tv_usec = 0)
# define timercmp(a, b, CMP) \
(((a)->tv_sec == (b)->tv_sec) ? \
((a)->tv_usec CMP (b)->tv_usec) : \
((a)->tv_sec CMP (b)->tv_sec))
#endif
#ifndef timeradd
# define timeradd(a, b, result) \
do { \
(result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
(result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
if ((result)->tv_usec >= 1000000) \
{ \
++(result)->tv_sec; \
(result)->tv_usec -= 1000000; \
} \
} while (0)
#endif
#ifndef timersub
# define timersub(a, b, result) \
do { \
(result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
(result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
if ((result)->tv_usec < 0) { \
--(result)->tv_sec; \
(result)->tv_usec += 1000000; \
} \
} while (0)
#endif
#ifndef CLICK_TIMEVAL_OPERATORS
inline timeval make_timeval(int sec, int usec) CLICK_DEPRECATED;
inline bool operator==(const timeval &a, const timeval &b) CLICK_DEPRECATED;
inline bool operator!=(const timeval &a, const timeval &b) CLICK_DEPRECATED;
inline bool operator<(const timeval &a, const timeval &b) CLICK_DEPRECATED;
inline bool operator<=(const timeval &a, const timeval &b) CLICK_DEPRECATED;
inline bool operator>(const timeval &a, const timeval &b) CLICK_DEPRECATED;
inline bool operator>=(const timeval &a, const timeval &b) CLICK_DEPRECATED;
inline timeval &operator+=(timeval &a, const timeval &b) CLICK_DEPRECATED;
inline timeval &operator-=(timeval &a, const timeval &b) CLICK_DEPRECATED;
inline timeval operator+(timeval a, const timeval &b) CLICK_DEPRECATED;
inline timeval operator-(timeval a, const timeval &b) CLICK_DEPRECATED;
inline struct timeval
make_timeval(int sec, int usec)
{
struct timeval tv;
tv.tv_sec = sec;
tv.tv_usec = usec;
return tv;
}
inline bool
operator==(const struct timeval &a, const struct timeval &b)
{
return a.tv_sec == b.tv_sec && a.tv_usec == b.tv_usec;
}
inline bool
operator!=(const struct timeval &a, const struct timeval &b)
{
return a.tv_sec != b.tv_sec || a.tv_usec != b.tv_usec;
}
inline bool
operator<(const struct timeval &a, const struct timeval &b)
{
return a.tv_sec < b.tv_sec || (a.tv_sec == b.tv_sec && a.tv_usec < b.tv_usec);
}
inline bool
operator<=(const struct timeval &a, const struct timeval &b)
{
return a.tv_sec < b.tv_sec || (a.tv_sec == b.tv_sec && a.tv_usec <= b.tv_usec);
}
inline bool
operator>=(const struct timeval &a, const struct timeval &b)
{
return a.tv_sec > b.tv_sec || (a.tv_sec == b.tv_sec && a.tv_usec >= b.tv_usec);
}
inline bool
operator>(const struct timeval &a, const struct timeval &b)
{
return a.tv_sec > b.tv_sec || (a.tv_sec == b.tv_sec && a.tv_usec > b.tv_usec);
}
inline struct timeval &
operator+=(struct timeval &a, const struct timeval &b)
{
timeradd(&a, &b, &a);
return a;
}
inline struct timeval &
operator-=(struct timeval &a, const struct timeval &b)
{
timersub(&a, &b, &a);
return a;
}
inline struct timeval
operator+(struct timeval a, const struct timeval &b)
{
timeradd(&a, &b, &a);
return a;
}
inline struct timeval
operator-(struct timeval a, const struct timeval &b)
{
timersub(&a, &b, &a);
return a;
}
#endif
CLICK_DECLS
class StringAccum;
StringAccum &operator<<(StringAccum &, const struct timeval &);
CLICK_ENDDECLS
// BYTE ORDER
#ifndef le16_to_cpu
# if CLICK_BYTE_ORDER == CLICK_LITTLE_ENDIAN
# define le16_to_cpu(x) (x)
# define cpu_to_le16(x) (x)
# define le32_to_cpu(x) (x)
# define cpu_to_le32(x) (x)
# elif CLICK_BYTE_ORDER == CLICK_BIG_ENDIAN && defined(__APPLE__)
# include <machine/byte_order.h>
# define le16_to_cpu(x) NXSwapShort((x))
# define cpu_to_le16(x) NXSwapShort((x))
# define le32_to_cpu(x) NXSwapInt((x))
# define cpu_to_le32(x) NXSwapInt((x))
# elif CLICK_BYTE_ORDER == CLICK_BIG_ENDIAN && HAVE_BYTESWAP_H
# include <byteswap.h>
# define le16_to_cpu(x) bswap_16((x))
# define cpu_to_le16(x) bswap_16((x))
# define le32_to_cpu(x) bswap_32((x))
# define cpu_to_le32(x) bswap_32((x))
# elif CLICK_BYTE_ORDER == CLICK_BIG_ENDIAN
# define le16_to_cpu(x) ((((x) & 0x00ff) << 8) | (((x) & 0xff00) >> 8))
# define cpu_to_le16(x) le16_to_cpu((x))
# define le32_to_cpu(x) (le16_to_cpu((x) >> 16) | (le16_to_cpu(x) << 16))
# define cpu_to_le32(x) le32_to_cpu((x))
# else
/* leave them undefined */
# endif
#endif
// CYCLE COUNTS
CLICK_DECLS
#if HAVE_INT64_TYPES
typedef uint64_t click_cycles_t;
#else
typedef uint32_t click_cycles_t;
#endif
inline click_cycles_t
click_get_cycles()
{
#if CLICK_LINUXMODULE && HAVE_INT64_TYPES && __i386__
uint64_t x;
__asm__ __volatile__ ("rdtsc" : "=A" (x));
return x;
#elif CLICK_LINUXMODULE && HAVE_INT64_TYPES && __x86_64__
uint32_t xlo, xhi;
__asm__ __volatile__ ("rdtsc" : "=a" (xlo), "=d" (xhi));
return xlo | (((uint64_t) xhi) << 32);
#elif CLICK_LINUXMODULE && __i386__
uint32_t xlo, xhi;
__asm__ __volatile__ ("rdtsc" : "=a" (xlo), "=d" (xhi));
return xlo;
#elif CLICK_BSDMODULE
return rdtsc();
#elif CLICK_USERLEVEL && HAVE_INT64_TYPES && __i386__
uint64_t x;
__asm__ __volatile__ ("rdtsc" : "=A" (x));
return x;
#elif CLICK_USERLEVEL && HAVE_INT64_TYPES && __x86_64__
uint32_t xlo, xhi;
__asm__ __volatile__ ("rdtsc" : "=a" (xlo), "=d" (xhi));
return xlo | (((uint64_t) xhi) << 32);
#elif CLICK_USERLEVEL && __i386__
uint32_t xlo, xhi;
__asm__ __volatile__ ("rdtsc" : "=a" (xlo), "=d" (xhi));
return xlo;
#elif CLICK_MINIOS
/* FIXME: Implement click_get_cycles for MiniOS */
return 0;
#else
// add other architectures here
return 0;
#endif
}
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,337 @@
#ifndef CLICK_HANDLER_HH
#define CLICK_HANDLER_HH 1
#include <click/string.hh>
CLICK_DECLS
class Element;
class ErrorHandler;
class Handler;
/** @file <click/handler.hh>
* @brief The Handler class for router handlers.
*/
typedef int (*HandlerCallback)(int operation, String &data, Element *element,
const Handler *handler, ErrorHandler *errh);
typedef String (*ReadHandlerCallback)(Element *handler, void *user_data);
typedef int (*WriteHandlerCallback)(const String &data, Element *element,
void *user_data, ErrorHandler *errh);
class Handler { public:
enum Flags {
f_read = 0x0001, ///< @brief Handler supports read operations.
f_write = 0x0002, ///< @brief Handler supports write operations.
f_read_param = 0x0004, ///< @brief Read handler takes parameters.
f_exclusive = 0, ///< @brief Handler is exclusive (the default):
/// router threads must stop while it is
/// called.
f_nonexclusive = 0x0020,///< @brief Handler is nonexclusive: router
/// threads don't need to stop while it is
/// called.
f_raw = 0x0040, ///< @brief Don't add newline to results.
f_read_private = 0x0080,///< @brief Read handler private (invisible
/// outside the router configuration).
f_write_private = 0x0100,///< @brief Write handler private (invisible
/// outside the router configuration).
f_deprecated = 0x0200, ///< @brief Handler is deprecated and available
/// only for compatibility.
f_uncommon = 0x0400, ///< @brief User interfaces should not display
/// handler by default.
f_calm = 0x0800, ///< @brief Read handler value changes rarely.
f_expensive = 0x1000, ///< @brief Read handler is expensive to call.
f_button = 0x2000, ///< @brief Write handler ignores data.
f_checkbox = 0x4000, ///< @brief Read/write handler is boolean and
/// should be rendered as a checkbox.
f_driver0 = 1U << 26,
f_driver1 = 1U << 27, ///< @brief Uninterpreted handler flags
/// available for drivers.
f_user_shift = 28,
f_user0 = 1U << f_user_shift,
///< @brief First uninterpreted handler flag
/// available for element-specific use.
/// Equals 1 << f_user_shift.
f_read_comprehensive = 0x0008,
f_write_comprehensive = 0x0010,
f_special = f_read | f_write | f_read_param | f_read_comprehensive | f_write_comprehensive
///< @brief These flags may not be set by
/// Router::set_handler_flags().
};
/** @brief Return this handler's name. */
inline const String &name() const {
return _name;
}
/** @brief Return this handler's flags.
*
* The result is a bitwise-or of flags from the Flags enumeration type. */
inline uint32_t flags() const {
return _flags;
}
/** @brief Return this handler's callback data.
* @param op either f_read or f_write. */
inline void *user_data(int op) const {
return op == f_write ? _write_user_data : _read_user_data;
}
/** @brief Return this handler's read callback data. */
inline void *read_user_data() const {
return _read_user_data;
}
/** @brief Return this handler's write callback data. */
inline void *write_user_data() const {
return _write_user_data;
}
/** @cond never */
inline void *user_data1() const CLICK_DEPRECATED;
inline void *user_data2() const CLICK_DEPRECATED;
/** @endcond never */
/** @brief Test if this is a valid read handler. */
inline bool readable() const {
return _flags & f_read;
}
/** @brief Test if this is a valid read handler that may accept
* parameters. */
inline bool read_param() const {
return _flags & f_read_param;
}
/** @brief Test if this is a public read handler.
*
* Private handlers may be not called from outside the router
* configuration. Handlers are public by default; to make a read handler
* private, add the f_read_private flag. */
inline bool read_visible() const {
return (_flags & (f_read | f_read_private)) == f_read;
}
/** @brief Test if this is a valid write handler. */
inline bool writable() const {
return _flags & f_write;
}
/** @brief Test if this is a public write handler.
*
* Private handlers may not be called from outside the router
* configuration. Handlers are public by default; to make a write handler
* private, add the f_write_private flag. */
inline bool write_visible() const {
return (_flags & (f_write | f_write_private)) == f_write;
}
/** @brief Test if this is a public read or write handler. */
inline bool visible() const {
return read_visible() || write_visible();
}
/** @brief Test if this handler can execute concurrently with other
* handlers. */
inline bool allow_concurrent_handlers() const {
return (_flags & f_nonexclusive);
}
/** @brief Test if this handler can execute concurrently with
* router threads. */
inline bool allow_concurrent_threads() const {
return (_flags & f_nonexclusive);
}
/** @brief Test if spaces should be preserved when calling this handler.
*
* Some Click drivers perform some convenience processing on handler
* values, for example by removing a terminating newline from write
* handler values or adding a terminating newline to read handler values.
* Raw handlers do not have their values manipulated in this way. Rawness
* is set by the f_raw flag.
*
* <ul>
* <li>The linuxmodule driver adds a terminating newline to non-raw read
* handler values, but does not modify raw read handlers' values in any
* way.</li>
* <li>The same applies to handler values returned by the userlevel
* driver's <tt>-h</tt> option.</li>
* <li>The linuxmodule driver removes an optional terminating newline from
* a one-line non-raw write handler value, but does not modify raw write
* handlers' values in any way.</li>
* </ul> */
inline bool raw() const {
return _flags & f_raw;
}
/** @brief Call a read handler, possibly with parameters.
* @param e element on which to call the handler
* @param param parameters, or an empty string if no parameters
* @param errh optional error handler
*
* The element must be nonnull; to call a global handler, pass the
* relevant router's Router::root_element(). @a errh may be null, in
* which case errors are reported to ErrorHandler::silent_handler(). */
String call_read(Element *e, const String &param, ErrorHandler *errh) const;
/** @brief Call a read handler without parameters.
* @param e element on which to call the handler
* @param errh error handler
*
* The element must be nonnull; to call a global handler, pass the
* relevant router's Router::root_element(). @a errh may be null, in
* which case errors are ignored. */
inline String call_read(Element *e, ErrorHandler *errh = 0) const {
return call_read(e, String(), errh);
}
/** @brief Call a write handler.
* @param value value to write to the handler
* @param e element on which to call the handler
* @param errh optional error handler
*
* The element must be nonnull; to call a global handler, pass the
* relevant router's Router::root_element(). @a errh may be null, in
* which case errors are reported to ErrorHandler::silent_handler(). */
int call_write(const String &value, Element *e, ErrorHandler *errh) const;
/** @brief Unparse this handler's name.
* @param e relevant element
*
* If @a e is an actual element, then returns "ENAME.HNAME", where ENAME
* is @a e's @link Element::name() name@endlink and HNAME is this
* handler's name(). Otherwise, just returns name(). */
String unparse_name(Element *e) const;
/** @brief Unparse a handler name.
* @param e relevant element, if any
* @param hname handler name
*
* If @a e is an actual element on some router, then returns
* "ENAME.hname", where ENAME is @a e's @link Element::name()
* name@endlink. Otherwise, just returns @a hname.*/
static String unparse_name(Element *e, const String &hname);
/** @brief Returns a handler incapable of doing anything.
*
* The returned handler returns false for readable() and writable() and
* has flags() of zero. */
static inline const Handler *blank_handler() {
return the_blank_handler;
}
/** @cond never */
enum {
h_read = f_read,
h_write = f_write,
h_read_param = f_read_param,
h_exclusive = f_exclusive,
h_nonexclusive = f_nonexclusive,
h_raw = f_raw,
h_read_private = f_read_private,
h_write_private = f_write_private,
h_deprecated = f_deprecated,
h_uncommon = f_uncommon,
h_calm = f_calm,
h_expensive = f_expensive,
h_button = f_button,
h_checkbox = f_checkbox,
h_driver_flag_0 = f_driver0,
h_driver_flag_1 = f_driver1,
h_user_flag_shift = f_user_shift,
h_user_flag_0 = f_user0,
h_read_comprehensive = f_read_comprehensive,
h_write_comprehensive = f_write_comprehensive,
h_special_flags = f_special
};
enum DeprecatedFlags {
OP_READ = f_read,
OP_WRITE = f_write,
READ_PARAM = f_read_param,
RAW = f_raw,
// READ_PRIVATE = f_read_private,
// WRITE_PRIVATE = f_write_private,
// DEPRECATED = f_deprecated,
// UNCOMMON = f_uncommon,
CALM = f_calm,
EXPENSIVE = f_expensive,
BUTTON = f_button,
CHECKBOX = f_checkbox,
USER_FLAG_SHIFT = f_user_shift,
USER_FLAG_0 = f_user0
};
enum CLICK_DEPRECATED {
EXCLUSIVE = f_exclusive,
NONEXCLUSIVE = f_nonexclusive
};
/** @endcond never */
/** @cond never */
/** @brief Call a read handler without parameters, passing new user_data().
* @param e element on which to call the handler
* @param new_user_data new user data
*
* This function should only be used for special purposes. It fails
* unless called on a handler created with a ReadHandlerCallback. */
inline String __call_read(Element *e, void *new_user_data) const {
assert((_flags & (f_read | f_read_comprehensive)) == f_read);
return _read_hook.r(e, new_user_data);
}
/** @endcond never */
private:
String _name;
union {
HandlerCallback h;
ReadHandlerCallback r;
} _read_hook;
union {
HandlerCallback h;
WriteHandlerCallback w;
} _write_hook;
void *_read_user_data;
void *_write_user_data;
uint32_t _flags;
int _use_count;
int _next_by_name;
static const Handler *the_blank_handler;
Handler(const String & = String());
inline void combine(const Handler &x);
inline bool compatible(const Handler &x) const;
friend class Router;
};
/* The largest size a write handler is allowed to have. */
#define LARGEST_HANDLER_WRITE 65536
typedef HandlerCallback HandlerHook CLICK_DEPRECATED;
typedef ReadHandlerCallback ReadHandlerHook CLICK_DEPRECATED;
typedef WriteHandlerCallback WriteHandlerHook CLICK_DEPRECATED;
/** @cond never */
inline void *
Handler::user_data1() const
{
return _read_user_data;
}
inline void *
Handler::user_data2() const
{
return _write_user_data;
}
/** @endcond never */
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,577 @@
// -*- c-basic-offset: 4; related-file-name: "../../lib/handlercall.cc" -*-
#ifndef CLICK_HANDLERCALL_HH
#define CLICK_HANDLERCALL_HH
#include <click/router.hh>
CLICK_DECLS
class VariableExpander;
/** @brief Convenience class for calling handlers.
*
* The HandlerCall class simplifies the process of calling Click handlers.
* (The lower-level interface is the Handler class.) HandlerCall is used in
* two ways: (1) to call handlers immediately via static member functions,
* and (2) to set up future handler calls via HandlerCall objects. The
* immediate handler call functions take handler names as arguments and
* perform all necessary error checks before calling handlers, if any. A
* HandlerCall object encapsulates a handler reference (possibly including
* parameters), again automating all necessary error checks.
*
* <h2>Immediate Handler Calls</h2>
*
* This example code shows how to use the HandlerCall functions for calling
* handlers immediately.
*
* @code
* class YourElement { ...
* Element *_other;
* }
*
* void YourElement::function() {
* // Call _other's "config" read handler.
* String result = HandlerCall::call_read(_other, "config");
*
* // The same, providing an error handler to print errors.
* ErrorHandler *errh = ErrorHandler::default_handler();
* result = HandlerCall::call_read(_other, "config", errh);
* // (Each function takes an optional last argument of "errh".)
*
* // Call the "foo.config" read handler. Search for element "foo" in
* // the current compound element context.
* result = HandlerCall::call_read("foo.config", this);
*
* // Call the global "config" read handler for the current router.
* result = HandlerCall::call_read("config", this);
*
* // Call _other's "stop" write handler with empty value.
* int success = HandlerCall::call_write(_other, "stop");
*
* // Call _other's "config" write handler with value "blah".
* success = HandlerCall::call_write(_other, "config", "blah");
*
* // Call the "foo.config" write handler with value "blah".
* success = HandlerCall::call_write("foo.config blah", this);
* // Or, alternately:
* success = HandlerCall::call_write("foo.config", "blah", this);
* }
* @endcode
*
* <h2>HandlerCall Objects</h2>
*
* This example code shows how to use the HandlerCall objects to call
* handlers with simplified error checking.
*
* @code
* class YourElement { ...
* HandlerCall _read_call;
* HandlerCall _write_call;
* }
*
* YourElement::YourElement()
* : _read_call(), _write_call() {
* }
*
* int YourElement::configure(Vector<String> &conf, ErrorHandler *errh) {
* return cp_va_kparse(conf, this, errh,
* "READ_CALL", cpkP, cpHandlerCallRead, &_read_call,
* "WRITE_CALL", cpkP, cpHandlerCallWrite, &_write_call,
* cpEnd);
* }
*
* int YourElement::initialize(ErrorHandler *errh) {
* if ((_read_call && _read_call.initialize_read(this, errh) < 0)
* || (_write_call && _write_call.initialize_write(this, errh) < 0))
* return -1;
* return 0;
* }
*
* void YourElement::function() {
* // call _read_call, print result
* if (_read_call)
* click_chatter("%s", _read_call.call_read());
*
* // call _write_call with error handler
* if (_write_call)
* _write_call.call_write(ErrorHandler::default_handler());
* }
* @endcode
*
* If usually your element's handler calls aren't used, you can save a small
* amount of space by using pointers to HandlerCall objects, as in this
* example. The cpHandlerCallPtrRead and cpHandlerCallPtrWrite types allow
* the _read_call and _write_call members to start out as null pointers.
*
* @code
* class YourElement { ...
* HandlerCall *_read_call;
* HandlerCall *_write_call;
* }
*
* YourElement::YourElement()
* : _read_call(0), _write_call(0) {
* }
*
* int YourElement::configure(Vector<String> &conf, ErrorHandler *errh) {
* return cp_va_kparse(conf, this, errh,
* "READ_CALL", cpkP, cpHandlerCallPtrRead, &_read_call,
* "WRITE_CALL", cpkP, cpHandlerCallPtrWrite, &_write_call,
* cpEnd);
* }
*
* int YourElement::initialize(ErrorHandler *errh) {
* if ((_read_call && _read_call->initialize_read(this, errh) < 0)
* || (_write_call && _write_call->initialize_write(this, errh) < 0))
* return -1;
* return 0;
* }
*
* void YourElement::cleanup(CleanupStage) {
* delete _read_call;
* delete _write_call;
* }
*
* void YourElement::function() {
* // call _read_call, print result
* if (_read_call)
* click_chatter("%s", _read_call->call_read());
*
* // call _write_call with error handler
* if (_write_call)
* _write_call->call_write(ErrorHandler::default_handler());
* }
* @endcode
*/
class HandlerCall { public:
/** @name Immediate Handler Calls */
//@{
static String call_read(Element *e, const String &hname,
ErrorHandler *errh = 0);
static String call_read(const String &hdesc, const Element *context,
ErrorHandler *errh = 0);
static int call_write(Element *e, const String &hname,
ErrorHandler *errh = 0);
static int call_write(Element *e, const String &hname, const String &value,
ErrorHandler *errh = 0);
static int call_write(const String &hdesc,
const Element *context, ErrorHandler *errh = 0);
static int call_write(const String &hdesc, const String &value,
const Element *context, ErrorHandler *errh = 0);
//@}
/** @brief Construct an empty HandlerCall.
*
* Any attempt to read, write, or initialize the HandlerCall will
* fail. */
HandlerCall()
: _e(0), _h(Handler::blank_handler()) {
}
/** @brief Construct a HandlerCall described by @a hdesc.
* @param hdesc handler description <tt>"[ename.]hname[ value]"</tt>
*
* Although the resulting HandlerCall isn't empty, it must be initialized
* before it can be used. It returns false for initialized(). The
* handler description is not checked for syntax errors, though;
* initialize() does that. */
HandlerCall(const String &hdesc)
: _e(reinterpret_cast<Element *>(4)), _h(Handler::blank_handler()),
_value(hdesc) {
}
enum Flags {
readable = Handler::f_read,
f_read = Handler::f_read,
writable = Handler::f_write,
f_write = Handler::f_write,
f_preinitialize = 4,
f_unquote_param = 8
};
/** @brief Initialize the HandlerCall.
* @param flags zero or more of f_read, f_write, f_preinitialize,
* f_unquote_param
* @param context optional element context
* @param errh optional error handler
* @return 0 on success, negative on failure
*
* Initializes the HandlerCall object. The handler description supplied
* to the constructor is parsed and checked for syntax errors. Any
* element reference is looked up relative to @a context, if any. (For
* example, if @a hdesc was "x.config" and @a context's name is
* "aaa/bbb/ccc", this will search for elements named aaa/bbb/x, aaa/x,
* and finally x. If @a context is null, then the description must refer
* to a global handler.) If f_read is set in @a flags, then there
* must be a read handler named appropriately; if f_write is set,
* then there must be a write handler. If f_unquote_param is set, then any
* parameters are unquoted.
*
* Initialization fails if the handler description was bogus (for
* example, an empty string, or something like "*#!$&!(#&$."), if the
* named handler does not exist, if a read handler description has
* parameters but the read handler doesn't actually take parameters, and
* so forth. If @a errh is nonnull, errors are reported there. The
* HandlerCall becomes empty on failure: empty() will return true, and
* (bool) *this will return false. Future call_read() and call_write()
* attempts will correctly fail.
*
* If the f_preinitialize flag is set, the initialize function will check
* whether the router's handlers are ready (Router::handlers_ready()).
* If handlers are not ready, then initialize() will check for syntax
* errors, but not actually look up the handler (since we don't know yet
* whether or not the handler exists). Absent a syntax error,
* initialize() will return 0 for success even though the HandlerCall
* remains uninitialized. */
int initialize(int flags, const Element *context, ErrorHandler *errh = 0);
/** @brief Initialize the HandlerCall for reading.
* @param context optional element context
* @param errh optional error handler
*
* Equivalent to @link initialize(int, const Element*, ErrorHandler*)
* initialize@endlink(f_read, @a context, @a errh). */
inline int initialize_read(const Element *context, ErrorHandler *errh = 0);
/** @brief Initialize the HandlerCall for writing.
* @param context optional element context
* @param errh optional error handler
*
* Equivalent to @link initialize(int, const Element*, ErrorHandler*)
* initialize@endlink(f_write, @a context, @a errh). */
inline int initialize_write(const Element *context, ErrorHandler *errh = 0);
typedef bool (HandlerCall::*unspecified_bool_type)() const;
/** @brief Test if HandlerCall is empty.
* @return True if HandlerCall is not empty, false otherwise.
*
* Valid HandlerCall objects have been successfully initialized. */
operator unspecified_bool_type() const {
return _h != Handler::blank_handler() || _e ? &HandlerCall::empty : 0;
}
/** @brief Test if HandlerCall is empty.
* @return True if HandlerCall is empty, false otherwise. */
bool empty() const {
return _h == Handler::blank_handler() && !_e;
}
/** @brief Test if HandlerCall is initialized.
* @return True if HandlerCall is initialized, false otherwise. */
bool initialized() const {
return _h != Handler::blank_handler();
}
/** @brief Call a read handler.
* @param errh optional error handler
* @return Read handler result.
*
* Fails and returns the empty string if this HandlerCall is invalid or
* not a read handler. If @a errh is nonnull, then any errors are
* reported there, whether from HandlerCall or the handler itself. */
inline String call_read(ErrorHandler *errh = 0) const;
/** @brief Call a write handler.
* @param errh optional error handler
* @return Write handler result.
*
* Fails and returns -EINVAL if this HandlerCall is invalid or not a
* write handler. If @a errh is nonnull, then any errors are reported
* there, whether from HandlerCall or the handler itself. */
inline int call_write(ErrorHandler *errh = 0) const;
/** @brief Call a write handler, expanding its argument.
* @param scope variable scope
* @param errh optional error handler
* @return Write handler result.
*
* The write value is expanded in @a scope before the handler is called.
* Fails and returns -EINVAL if this HandlerCall is invalid or not a
* write handler. If @a errh is nonnull, then any errors are reported
* there, whether from HandlerCall or the handler itself. */
inline int call_write(const VariableExpander &scope, ErrorHandler *errh = 0) const;
/** @brief Call a write handler with an additional value.
* @param value_ext write value extension
* @param errh optional error handler
* @return Write handler result.
*
* The @a value_ext is appended to the write value before the handler is
* called. (For example, consider a handler with description "a.set
* value". call_write("foo") will call "a.set value foo".) Fails and
* returns -EINVAL if this HandlerCall is invalid or not a write handler.
* If @a errh is nonnull, then any errors are reported there, whether
* from HandlerCall or the handler itself. */
inline int call_write(const String &value_ext, ErrorHandler *errh = 0) const;
/** @brief Create and initialize a HandlerCall from @a hdesc.
* @param hcall stores the HandlerCall result
* @param hdesc handler description "[ename.]hname[ value]"
* @param flags initialization flags (f_read, f_write, f_preinitialize)
* @param context optional element context
* @param errh optional error handler
* @return 0 on success, -EINVAL on failure
*
* Creates a HandlerCall and initializes it. Behaves somewhat like:
*
* @code
* hcall = new HandlerCall(hdesc);
* return hcall->initialize(flags, context, errh);
* @endcode
*
* However, (1) if initialization fails, then @a hcall is untouched; and
* (2) if initialization succeeds and @a hcall is not null, then the
* existing HandlerCall is assigned so that it corresponds to the new one
* (no new memory allocations).
*
* If @a errh is nonnull, then any errors are reported there. */
static int reset(HandlerCall *&hcall, const String &hdesc, int flags,
const Element *context, ErrorHandler *errh = 0);
/** @brief Create and initialize a HandlerCall on element @a e.
* @param hcall stores the HandlerCall result
* @param e relevant element, if any
* @param hname handler name
* @param value handler value
* @param flags initialization flags (f_read, f_write, f_preinitialize)
* @param errh optional error handler
* @return 0 on success, -EINVAL on failure
*
* Creates a HandlerCall and initializes it. Behaves analogously to
* reset(HandlerCall*&, const String&, int, const Element*, ErrorHandler*). */
static int reset(HandlerCall *&hcall,
Element *e, const String &hname, const String &value,
int flags, ErrorHandler *errh = 0);
/** @brief Create and initialize a read HandlerCall from @a hdesc.
* @param hcall stores the HandlerCall result
* @param hdesc handler description "[ename.]hdesc[ param]"
* @param context optional element context
* @param errh optional error handler
* @return 0 on success, -EINVAL on failure
*
* Equivalent to
* @link reset(HandlerCall*&, const String&, int, const Element*, ErrorHandler*) reset@endlink(@a hcall, @a hdesc, f_read, @a context, @a errh). */
static inline int reset_read(HandlerCall *&hcall, const String &hdesc,
const Element *context, ErrorHandler *errh = 0);
/** @brief Create and initialize a read HandlerCall from @a hdesc.
* @param hcall stores the HandlerCall result
* @param e relevant element, if any
* @param hname handler name
* @param errh optional error handler
* @return 0 on success, -EINVAL on failure
*
* Equivalent to
* @link reset(HandlerCall*&, Element*, const String&, const String&, int, ErrorHandler*) reset@endlink(@a hcall, @a e, @a hname, String(), f_read, @a context, @a errh). */
static inline int reset_read(HandlerCall *&hcall,
Element *e, const String &hname,
ErrorHandler *errh = 0);
/** @brief Create and initialize a write HandlerCall from @a hdesc.
* @param hcall stores the HandlerCall result
* @param hdesc handler description "[ename.]hdesc[ value]"
* @param context optional element context
* @param errh optional error handler
* @return 0 on success, -EINVAL on failure
*
* Equivalent to
* @link reset(HandlerCall*&, const String&, int, const Element*, ErrorHandler*) reset@endlink(@a hcall, @a hdesc, f_write, @a context, @a errh). */
static inline int reset_write(HandlerCall *&hcall, const String &hdesc,
const Element *context, ErrorHandler *errh = 0);
/** @brief Create and initialize a read HandlerCall from @a hdesc.
* @param hcall stores the HandlerCall result
* @param e relevant element, if any
* @param hname handler name
* @param value write handler value
* @param errh optional error handler
* @return 0 on success, -EINVAL on failure
*
* Equivalent to
* @link reset(HandlerCall*&, Element*, const String&, const String&, int, ErrorHandler*) reset@endlink(@a hcall, @a e, @a hname, @ value, f_write, @a context, @a errh). */
static inline int reset_write(HandlerCall *&hcall,
Element *e, const String &hname,
const String &value = String(),
ErrorHandler *errh = 0);
/** @brief Return the Element corresponding to this HandlerCall.
*
* Returns null if invalid. A global handler may return some
* Router::root_element() or null. */
Element *element() const {
return _e;
}
/** @brief Return the Handler corresponding to this HandlerCall.
*
* Returns Handler::blank_handler() if invalid. */
const Handler *handler() const {
return _h;
}
/** @brief Return the write handler value and/or read handler parameters.
*
* Returns the empty string if invalid. */
const String &value() const {
return initialized() ? _value : String::make_empty();
}
/** @brief Sets the write handler value and/or read handler parameters.
* @param value new value and/or parameters
*
* Does nothing if invalid. */
void set_value(const String &value) {
if (initialized())
_value = value;
}
/** @brief Return a String that will parse into an equivalent HandlerCall.
*
* Will work even if the HandlerCall has not been initialized. */
String unparse() const;
/** @brief Make this HandlerCall empty.
*
* Subsequent attempts to read, write, or initialize the HandlerCall will
* fail. */
void clear() {
_e = 0;
_h = Handler::blank_handler();
_value = String();
}
/** @cond never */
enum {
CHECK_READ = f_read, OP_READ = f_read, h_read = f_read,
CHECK_WRITE = f_write, OP_WRITE = f_write, h_write = f_write,
PREINITIALIZE = f_preinitialize, h_preinitialize = f_preinitialize,
UNQUOTE_PARAM = f_unquote_param, h_unquote_param = f_unquote_param
};
/** @endcond never */
private:
Element *_e;
const Handler *_h;
String _value;
int parse(int flags, Element*, ErrorHandler*);
int assign(Element*, const String&, const String&, int flags, ErrorHandler*);
};
inline int
HandlerCall::reset_read(HandlerCall*& hcall, const String& hdesc, const Element* context, ErrorHandler* errh)
{
return reset(hcall, hdesc, f_read, context, errh);
}
inline int
HandlerCall::reset_write(HandlerCall*& hcall, const String& hdesc, const Element* context, ErrorHandler* errh)
{
return reset(hcall, hdesc, f_write, context, errh);
}
inline int
HandlerCall::reset_read(HandlerCall*& hcall, Element* e, const String& hname, ErrorHandler* errh)
{
return reset(hcall, e, hname, String(), f_read, errh);
}
inline int
HandlerCall::reset_write(HandlerCall*& hcall, Element* e, const String& hname, const String& value, ErrorHandler* errh)
{
return reset(hcall, e, hname, value, f_write, errh);
}
inline int
HandlerCall::initialize_read(const Element* context, ErrorHandler* errh)
{
return initialize(f_read, context, errh);
}
inline int
HandlerCall::initialize_write(const Element* context, ErrorHandler* errh)
{
return initialize(f_write, context, errh);
}
inline String
HandlerCall::call_read(ErrorHandler *errh) const
{
return _h->call_read(_e, _value, errh);
}
inline int
HandlerCall::call_write(ErrorHandler *errh) const
{
return _h->call_write(_value, _e, errh);
}
String cp_expand(const String &str, const VariableExpander &env, bool expand_quote, int depth);
inline int
HandlerCall::call_write(const VariableExpander &scope, ErrorHandler *errh) const
{
return _h->call_write(cp_expand(_value, scope, false, 0), _e, errh);
}
inline int
HandlerCall::call_write(const String &value_ext, ErrorHandler *errh) const
{
if (_value && value_ext)
return _h->call_write(_value + " " + value_ext, _e, errh);
else
return _h->call_write(_value ? _value : value_ext, _e, errh);
}
/** @brief Call a write handler specified by element and handler name.
* @param e relevant element, if any
* @param hname handler name
* @param errh optional error handler
* @return handler result, or -EINVAL on error
*
* Searches for a write handler named @a hname on element @a e. If the
* handler exists, calls it (with empty write value) and returns the result.
* If @a errh is nonnull, then errors, such as a missing handler or a
* read-only handler, are reported there. If @a e is some router's @link
* Router::root_element() root element@endlink, calls the global write
* handler named @a hname on that router. */
inline int
HandlerCall::call_write(Element *e, const String &hname, ErrorHandler *errh)
{
return call_write(e, hname, String(), errh);
}
/** @class HandlerCallArg
@brief Parser class for handler call specifications.
The constructor argument should generally be either HandlerCall::writable or
HandlerCall::readable. For example:
@code
HandlerCall end_h;
... Args(...) ...
.read("END_CALL", HandlerCallArg(HandlerCall::writable), end_h)
...
@endcode */
struct HandlerCallArg {
HandlerCallArg(int f)
: flags(f) {
}
bool parse(const String &str, HandlerCall &result, const ArgContext &args);
int flags;
};
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,103 @@
// -*- related-file-name: "../../lib/hashallocator.cc" -*-
#ifndef CLICK_HASHALLOCATOR_HH
#define CLICK_HASHALLOCATOR_HH
#if HAVE_VALGRIND && HAVE_VALGRIND_MEMCHECK_H
# include <valgrind/memcheck.h>
#endif
CLICK_DECLS
class HashAllocator { public:
HashAllocator(size_t size);
~HashAllocator();
inline void increase_size(size_t new_size) {
assert(!_free && !_buffer && new_size >= _size);
_size = new_size;
}
inline void *allocate();
inline void deallocate(void *p);
void swap(HashAllocator &x);
private:
struct link {
link *next;
};
struct buffer {
buffer *next;
size_t pos;
size_t maxpos;
};
enum {
min_buffer_size = 1024,
#if CLICK_LINUXMODULE
max_buffer_size = 16384,
#else
max_buffer_size = 1048576,
#endif
min_nelements = 8
};
link *_free;
buffer *_buffer;
size_t _size;
void *hard_allocate();
HashAllocator(const HashAllocator &x);
HashAllocator &operator=(const HashAllocator &x);
};
template <size_t size>
class SizedHashAllocator : public HashAllocator { public:
SizedHashAllocator()
: HashAllocator(size) {
}
};
inline void *HashAllocator::allocate()
{
if (link *l = _free) {
#ifdef VALGRIND_MEMPOOL_ALLOC
VALGRIND_MEMPOOL_ALLOC(this, l, _size);
VALGRIND_MAKE_MEM_DEFINED(&l->next, sizeof(l->next));
#endif
_free = l->next;
#ifdef VALGRIND_MAKE_MEM_DEFINED
VALGRIND_MAKE_MEM_UNDEFINED(&l->next, sizeof(l->next));
#endif
return l;
} else if (_buffer && _buffer->pos < _buffer->maxpos) {
void *data = reinterpret_cast<char *>(_buffer) + _buffer->pos;
_buffer->pos += _size;
#ifdef VALGRIND_MEMPOOL_ALLOC
VALGRIND_MEMPOOL_ALLOC(this, data, _size);
#endif
return data;
} else
return hard_allocate();
}
inline void HashAllocator::deallocate(void *p)
{
if (p) {
reinterpret_cast<link *>(p)->next = _free;
_free = reinterpret_cast<link *>(p);
#ifdef VALGRIND_MEMPOOL_FREE
VALGRIND_MEMPOOL_FREE(this, p);
#endif
}
}
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,103 @@
#ifndef CLICK_HASHCODE_HH
#define CLICK_HASHCODE_HH
CLICK_DECLS
// Notes about the hashcode template: On GCC 4.3.0, "template <>" is required
// on the specializations or they aren't used. Just plain overloaded
// functions aren't used. The specializations must be e.g. "const char &",
// not "char", or GCC complains about a specialization not matching the
// general template. The main template takes a const reference for two
// reasons. First, providing both "hashcode_t hashcode(T)" and "hashcode_t
// hashcode(const T&)" leads to ambiguity errors. Second, providing only
// "hashcode_t hashcode(T)" is slower by looks like 8% when T is a String,
// because of copy constructors; for types with more expensive non-default
// copy constructors this would probably be worse.
typedef size_t hashcode_t; ///< Typical type for a hashcode() value.
template <typename T>
inline hashcode_t hashcode(T const &x) {
return x.hashcode();
}
template <>
inline hashcode_t hashcode(char const &x) {
return x;
}
template <>
inline hashcode_t hashcode(signed char const &x) {
return x;
}
template <>
inline hashcode_t hashcode(unsigned char const &x) {
return x;
}
template <>
inline hashcode_t hashcode(short const &x) {
return x;
}
template <>
inline hashcode_t hashcode(unsigned short const &x) {
return x;
}
template <>
inline hashcode_t hashcode(int const &x) {
return x;
}
template <>
inline hashcode_t hashcode(unsigned const &x) {
return x;
}
template <>
inline hashcode_t hashcode(long const &x) {
return x;
}
template <>
inline hashcode_t hashcode(unsigned long const &x) {
return x;
}
#if HAVE_LONG_LONG
template <>
inline hashcode_t hashcode(long long const &x) {
return (x >> 32) ^ x;
}
template <>
inline hashcode_t hashcode(unsigned long long const &x) {
return (x >> 32) ^ x;
}
#endif
#if HAVE_INT64_TYPES && !HAVE_INT64_IS_LONG && !HAVE_INT64_IS_LONG_LONG
template <>
inline hashcode_t hashcode(int64_t const &x) {
return (x >> 32) ^ x;
}
template <>
inline hashcode_t hashcode(uint64_t const &x) {
return (x >> 32) ^ x;
}
#endif
template <typename T>
inline hashcode_t hashcode(T * const &x) {
return reinterpret_cast<uintptr_t>(x) >> 3;
}
template <typename T>
inline typename T::key_const_reference hashkey(const T &x) {
return x.hashkey();
}
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,724 @@
#ifndef CLICK_HASHCONTAINER_HH
#define CLICK_HASHCONTAINER_HH
#include <click/glue.hh>
#include <click/hashcode.hh>
#include <click/libdivide.h>
#if CLICK_DEBUG_HASHMAP
# define click_hash_assert(x) assert(x)
#else
# define click_hash_assert(x)
#endif
CLICK_DECLS
template <typename T> class HashContainer_adapter;
template <typename T, typename A = HashContainer_adapter<T> > class HashContainer_const_iterator;
template <typename T, typename A = HashContainer_adapter<T> > class HashContainer_iterator;
template <typename T, typename A = HashContainer_adapter<T> > class HashContainer;
/** @cond never */
template <typename T, typename A>
class HashContainer_rep : public A {
T **buckets;
uint32_t nbuckets;
mutable uint32_t first_bucket;
size_t size;
libdivide_u32_t bucket_divider;
friend class HashContainer<T, A>;
friend class HashContainer_const_iterator<T, A>;
friend class HashContainer_iterator<T, A>;
};
/** @endcond */
template <typename T>
class HashContainer_adapter { public:
typedef typename T::key_type key_type;
typedef typename T::key_const_reference key_const_reference;
static T *&hashnext(T *e) {
return e->_hashnext;
}
static key_const_reference hashkey(const T *e) {
return e->hashkey();
}
static bool hashkeyeq(const key_type &a, const key_type &b) {
return a == b;
}
};
/** @class HashContainer
@brief Intrusive hash table template.
The HashContainer template implements a hash table or associative array
suitable for use in the kernel or at user level.
HashContainer is <em>intrusive.</em> This means it does not manage its
contents' memory. While non-intrusive containers are more common in the
STL, intrusive containers make it simple to store objects in more than one
container at a time.
Unlike many hash tables HashContainer does not automatically grow itself to
maintain good lookup performance. Its users are expected to call rehash()
when appropriate. See unbalanced().
With the default adapter type (A), the template type T must:
<ul>
<li>Define a "key_type" type that supports equality.</li>
<li>Define a "key_const_reference" type, usually the same as "key_type."</li>
<li>Contain a member "T *_hashnext" accessible to HashContainer_adapter<T>.</li>
<li>Define a "hashkey()" member function that returns the relevant hash key.
This function must have return type "key_const_reference."</li>
</ul>
These requirements can be changed by supplying a different A, or adapter,
type.
HashContainer can store multiple elements with the same key, although this
is not the normal use. An element stored in a HashContainer should not
modify its key.
HashContainer is used to implement Click's HashTable template.
*/
template <typename T, typename A>
class HashContainer { public:
/** @brief Key type. */
typedef typename A::key_type key_type;
/** @brief Value type.
*
* Must meet the HashContainer requirements defined by type A. */
typedef T value_type;
/** @brief Type of sizes. */
typedef size_t size_type;
/** @brief Type of bucket counts. */
typedef uint32_t bucket_count_type;
enum {
#if CLICK_LINUXMODULE
max_bucket_count = 4194303,
#else
max_bucket_count = (bucket_count_type) -1,
#endif
initial_bucket_count = 63
};
/** @brief Construct an empty HashContainer. */
HashContainer();
/** @brief Construct an empty HashContainer with at least @a n buckets. */
explicit HashContainer(bucket_count_type n);
/** @brief Destroy the HashContainer. */
~HashContainer();
/** @brief Return the number of elements stored. */
inline size_type size() const {
return _rep.size;
}
/** @brief Return true iff size() == 0. */
inline bool empty() const {
return _rep.size == 0;
}
/** @brief Return the number of buckets. */
inline bucket_count_type bucket_count() const {
return _rep.nbuckets;
}
/** @brief Return the number of elements in bucket @a n. */
inline size_type bucket_size(bucket_count_type n) const {
click_hash_assert(n < _rep.nbuckets);
size_type s = 0;
for (T *element = _rep.buckets[n]; element; element = _rep.hashnext(element))
++s;
return s;
}
/** @brief Return the bucket number containing elements with @a key. */
bucket_count_type bucket(const key_type &key) const;
/** @brief Return true if this HashContainer should be rebalanced. */
inline bool unbalanced() const {
return _rep.size > 2 * _rep.nbuckets && _rep.nbuckets < max_bucket_count;
}
typedef HashContainer_const_iterator<T, A> const_iterator;
typedef HashContainer_iterator<T, A> iterator;
/** @brief Return an iterator for the first element in the container.
*
* @note HashContainer iterators return elements in random order. */
inline iterator begin();
/** @overload */
inline const_iterator begin() const;
/** @brief Return an iterator for the end of the container.
* @invariant end().live() == false */
inline iterator end();
/** @overload */
inline const_iterator end() const;
/** @brief Return an iterator for the first element in bucket @a n. */
inline iterator begin(bucket_count_type n);
/** @overload */
inline const_iterator begin(bucket_count_type n) const;
/** @brief Test if an element with key @a key exists in the table. */
inline bool contains(const key_type& key) const;
/** @brief Return the number of elements with key @a key in the table. */
inline size_type count(const key_type& key) const;
/** @brief Return an iterator for an element with @a key, if any.
*
* If no element with @a key exists in the table, find() returns an
* iterator that compares equal to end(). However, this iterator is
* special, and can also be used to efficiently insert an element with key
* @a key. In particular, the return value of find() always has
* can_insert(), and can thus be passed to insert_at() or set(). (It
* will insert elements at the head of the relevant bucket.) */
inline iterator find(const key_type &key);
/** @overload */
inline const_iterator find(const key_type &key) const;
/** @brief Return an iterator for an element with key @a key, if any.
*
* Like find(), but additionally moves any found element to the head of
* its bucket, possibly speeding up future lookups. */
inline iterator find_prefer(const key_type &key);
/** @brief Return an element for @a key, if any.
*
* Returns null if no element for @a key currently exists. Equivalent
* to find(key).get(). */
inline T *get(const key_type &key) const;
/** @brief Insert an element at position @a it.
* @param it iterator
* @param element element
* @pre @a it.can_insert()
* @pre @a it.bucket() == bucket(@a element->hashkey())
* @pre @a element != NULL
* @pre @a element is not already in the HashContainer
*
* Inserts @a element at the position in the hash table indicated by @a
* it. For instance, if @a it == begin(@em n) for some bucket number @em
* n, then @a element becomes the first element in bucket @em n. Other
* elements in the bucket, if any, are chained along.
*
* On return, @a it is updated to point immediately after @a element.
* If @a it was not live before, then it will not be live after.
*
* @note HashContainer never automatically rehashes itself, so element
* insertion leaves any existing iterators valid. For best performance,
* however, users must call balance() to resize the container when it
* becomes unbalanced(). */
inline void insert_at(iterator &it, T *element);
/** @brief Replace the element at position @a it with @a element.
* @param it iterator
* @param element element (can be null)
* @param balance whether to balance the hash table
* @return the previous value of it.get()
* @pre @a it.can_insert()
* @pre @a it.bucket() == bucket(@a element->hashkey())
* @pre @a element is not already in the HashContainer
*
* Replaces the element pointed to by @a it with @a element, and returns
* the former element. If @a element is null the former element is
* removed. If there is no former element then @a element is inserted.
* When inserting an element with @a balance true, set() may rebalance the
* hash table.
*
* As a side effect, @a it is advanced to point at the newly inserted @a
* element. If @a element is null, then @a it is advanced to point at the
* next element as by ++@a it. */
T *set(iterator &it, T *element, bool balance = false);
/** @brief Replace the element with @a element->hashkey() with @a element.
* @param element element
* @return the previous value of find(@a element->hashkey()).get()
* @pre @a element is not already in the HashContainer
*
* Finds an element with the same hashkey as @a element, removes it from
* the HashContainer, and replaces it with @a element. If there is no
* former element then @a element is inserted. */
inline T *set(T *element);
/** @brief Remove the element at position @a it.
* @param it iterator
* @return the previous value of it.get()
*
* As a side effect, @a it is advanced to the next element as by ++@a it. */
inline T *erase(iterator &it);
/** @brief Remove an element with hashkey @a key.
* @return the element removed, if any
*
* Roughly equivalent to erase(find(key)). */
inline T *erase(const key_type &key);
/** @brief Removes all elements from the container.
* @post size() == 0 */
void clear();
/** @brief Swaps the contents of *this and @a x. */
inline void swap(HashContainer<T, A> &x);
/** @brief Rehash the table, ensuring it contains at least @a n buckets.
*
* If @a n < bucket_count(), this function may make the hash table
* slower.
*
* @note Rehashing invalidates all existing iterators. */
void rehash(bucket_count_type n);
/** @brief Rehash the table if it is unbalanced.
*
* @note Rehashing invalidates all existing iterators. */
inline void balance() {
if (unbalanced())
rehash(bucket_count() + 1);
}
private:
HashContainer_rep<T, A> _rep;
HashContainer(const HashContainer<T, A> &);
HashContainer<T, A> &operator=(const HashContainer<T, A> &);
friend class HashContainer_iterator<T, A>;
friend class HashContainer_const_iterator<T, A>;
};
/** @class HashContainer_const_iterator
* @brief The const_iterator type for HashContainer. */
template <typename T, typename A>
class HashContainer_const_iterator { public:
typedef typename HashContainer<T, A>::size_type size_type;
typedef typename HashContainer<T, A>::bucket_count_type bucket_count_type;
/** @brief Construct an uninitialized iterator. */
HashContainer_const_iterator() {
}
/** @brief Return a pointer to the element, null if *this == end(). */
T *get() const {
return _element;
}
/** @brief Return a pointer to the element, null if *this == end(). */
T *operator->() const {
return _element;
}
/** @brief Return a reference to the element.
* @pre *this != end() */
T &operator*() const {
return *_element;
}
/** @brief Return true iff *this != end(). */
inline bool live() const {
return _element;
}
typedef T *(HashContainer_const_iterator::*unspecified_bool_type)() const;
/** @brief Return true iff *this != end(). */
inline operator unspecified_bool_type() const {
return _element ? &HashContainer_const_iterator::get : 0;
}
/** @brief Return the corresponding HashContainer. */
const HashContainer<T, A> *hashcontainer() const {
return _hc;
}
/** @brief Return the bucket number this iterator is in. */
bucket_count_type bucket() const {
return _bucket;
}
/** @brief Advance this iterator to the next element. */
void operator++() {
if (_element && _hc->_rep.hashnext(_element)) {
_pprev = &_hc->_rep.hashnext(_element);
_element = *_pprev;
} else if (_bucket != _hc->_rep.nbuckets) {
for (++_bucket; _bucket != _hc->_rep.nbuckets; ++_bucket)
if (*(_pprev = &_hc->_rep.buckets[_bucket])) {
_element = *_pprev;
return;
}
_element = 0;
}
}
/** @brief Advance this iterator to the next element. */
void operator++(int) {
++*this;
}
private:
T *_element;
T **_pprev;
bucket_count_type _bucket;
const HashContainer<T, A> *_hc;
inline HashContainer_const_iterator(const HashContainer<T, A> *hc)
: _hc(hc) {
_bucket = hc->_rep.first_bucket;
_pprev = &hc->_rep.buckets[_bucket];
if (unlikely(_bucket == hc->_rep.nbuckets))
_element = 0;
else if (!(_element = *_pprev)) {
(*this)++;
hc->_rep.first_bucket = _bucket;
}
}
inline HashContainer_const_iterator(const HashContainer<T, A> *hc, bucket_count_type b, T **pprev, T *element)
: _element(element), _pprev(pprev), _bucket(b), _hc(hc) {
click_hash_assert((!_pprev && !_element) || *_pprev == _element);
}
friend class HashContainer<T, A>;
friend class HashContainer_iterator<T, A>;
};
/** @class HashContainer_iterator
@brief The iterator type for HashContainer. */
template <typename T, typename A>
class HashContainer_iterator : public HashContainer_const_iterator<T, A> { public:
typedef HashContainer_const_iterator<T, A> inherited;
/** @brief Construct an uninitialized iterator. */
HashContainer_iterator() {
}
/** @brief Return true iff elements can be inserted here.
*
* Specifically, returns true iff this iterator is valid to pass to
* HashContainer::insert_at() or HashContainer::set(). All live()
* iterators can_insert(), but some !live() iterators can_insert() as
* well. */
bool can_insert() const {
return this->_bucket < this->_hc->bucket_count();
}
/** @brief Return the corresponding HashContainer. */
HashContainer<T, A> *hashcontainer() const {
return const_cast<HashContainer<T, A> *>(this->_hc);
}
private:
inline HashContainer_iterator(HashContainer<T, A> *hc)
: inherited(hc) {
}
inline HashContainer_iterator(HashContainer<T, A> *hc, typename inherited::bucket_count_type b, T **pprev, T *element)
: inherited(hc, b, pprev, element) {
}
friend class HashContainer<T, A>;
};
template <typename T, typename A>
HashContainer<T, A>::HashContainer()
{
_rep.size = 0;
_rep.nbuckets = initial_bucket_count;
_rep.buckets = (T **) CLICK_LALLOC(sizeof(T *) * _rep.nbuckets);
_rep.first_bucket = _rep.nbuckets;
_rep.bucket_divider = libdivide_u32_gen(_rep.nbuckets);
click_hash_assert(_rep.nbuckets == libdivide_u32_recover(&_rep.bucket_divider));
for (bucket_count_type b = 0; b < _rep.nbuckets; ++b)
_rep.buckets[b] = 0;
}
template <typename T, typename A>
HashContainer<T, A>::HashContainer(bucket_count_type nb)
{
bucket_count_type b = 1;
while (b < nb && b < max_bucket_count)
b = ((b + 1) << 1) - 1;
_rep.size = 0;
_rep.nbuckets = b;
_rep.buckets = (T **) CLICK_LALLOC(sizeof(T *) * _rep.nbuckets);
_rep.first_bucket = _rep.nbuckets;
_rep.bucket_divider = libdivide_u32_gen(_rep.nbuckets);
click_hash_assert(_rep.nbuckets == libdivide_u32_recover(&_rep.bucket_divider));
for (b = 0; b < _rep.nbuckets; ++b)
_rep.buckets[b] = 0;
}
template <typename T, typename A>
HashContainer<T, A>::~HashContainer()
{
CLICK_LFREE(_rep.buckets, sizeof(T *) * _rep.nbuckets);
}
template <typename T, typename A>
inline typename HashContainer<T, A>::bucket_count_type
HashContainer<T, A>::bucket(const key_type &key) const
{
bucket_count_type h = hashcode(key);
bucket_count_type d = libdivide_u32_do(h, &_rep.bucket_divider);
bucket_count_type r = h - _rep.nbuckets * d;
click_hash_assert(_rep.nbuckets == libdivide_u32_recover(&_rep.bucket_divider));
click_hash_assert(r == h % _rep.nbuckets);
return r;
}
template <typename T, typename A>
inline typename HashContainer<T, A>::const_iterator
HashContainer<T, A>::begin() const
{
return const_iterator(this);
}
template <typename T, typename A>
inline typename HashContainer<T, A>::iterator
HashContainer<T, A>::begin()
{
return iterator(this);
}
template <typename T, typename A>
inline typename HashContainer<T, A>::const_iterator
HashContainer<T, A>::end() const
{
return const_iterator(this, -1, 0, 0);
}
template <typename T, typename A>
inline typename HashContainer<T, A>::iterator
HashContainer<T, A>::end()
{
return iterator(this, -1, 0, 0);
}
template <typename T, typename A>
inline typename HashContainer<T, A>::iterator
HashContainer<T, A>::begin(bucket_count_type b)
{
click_hash_assert(b < _rep.nbuckets);
return iterator(this, b, &_rep.buckets[b], _rep.buckets[b]);
}
template <typename T, typename A>
inline typename HashContainer<T, A>::const_iterator
HashContainer<T, A>::begin(bucket_count_type b) const
{
click_hash_assert(b < _rep.nbuckets);
return const_iterator(this, b, &_rep.buckets[b], _rep.buckets[b]);
}
template <typename T, typename A>
inline bool HashContainer<T, A>::contains(const key_type& key) const
{
bucket_count_type b = bucket(key);
T **pprev;
for (pprev = &_rep.buckets[b]; *pprev; pprev = &_rep.hashnext(*pprev))
if (_rep.hashkeyeq(_rep.hashkey(*pprev), key))
return true;
return false;
}
template <typename T, typename A>
inline typename HashContainer<T, A>::size_type
HashContainer<T, A>::count(const key_type& key) const
{
bucket_count_type b = bucket(key);
size_t c = 0;
T **pprev;
for (pprev = &_rep.buckets[b]; *pprev; pprev = &_rep.hashnext(*pprev))
c += _rep.hashkeyeq(_rep.hashkey(*pprev), key);
return c;
}
template <typename T, typename A>
inline typename HashContainer<T, A>::iterator
HashContainer<T, A>::find(const key_type &key)
{
bucket_count_type b = bucket(key);
T **pprev;
for (pprev = &_rep.buckets[b]; *pprev; pprev = &_rep.hashnext(*pprev))
if (_rep.hashkeyeq(_rep.hashkey(*pprev), key))
return iterator(this, b, pprev, *pprev);
return iterator(this, b, &_rep.buckets[b], 0);
}
template <typename T, typename A>
inline typename HashContainer<T, A>::const_iterator
HashContainer<T, A>::find(const key_type &key) const
{
return const_cast<HashContainer<T, A> *>(this)->find(key);
}
template <typename T, typename A>
inline typename HashContainer<T, A>::iterator
HashContainer<T, A>::find_prefer(const key_type &key)
{
bucket_count_type b = bucket(key);
T **pprev;
for (pprev = &_rep.buckets[b]; *pprev; pprev = &_rep.hashnext(*pprev))
if (_rep.hashkeyeq(_rep.hashkey(*pprev), key)) {
T *element = *pprev;
*pprev = _rep.hashnext(element);
_rep.hashnext(element) = _rep.buckets[b];
_rep.buckets[b] = element;
return iterator(this, b, &_rep.buckets[b], element);
}
return iterator(this, b, &_rep.buckets[b], 0);
}
template <typename T, typename A>
inline T *HashContainer<T, A>::get(const key_type &key) const
{
return find(key).get();
}
template <typename T, typename A>
T *HashContainer<T, A>::set(iterator &it, T *element, bool balance)
{
click_hash_assert(it._hc == this && it._bucket < _rep.nbuckets);
click_hash_assert(bucket(_rep.hashkey(element)) == it._bucket);
click_hash_assert(!it._element || _rep.hashkeyeq(_rep.hashkey(element), _rep.hashkey(it._element)));
T *old = it.get();
if (unlikely(old == element))
return old;
if (!element) {
--_rep.size;
if (!(*it._pprev = it._element = _rep.hashnext(old)))
++it;
return old;
}
if (old)
_rep.hashnext(element) = _rep.hashnext(old);
else {
++_rep.size;
if (unlikely(unbalanced()) && balance) {
rehash(bucket_count() + 1);
it._bucket = bucket(_rep.hashkey(element));
it._pprev = &_rep.buckets[it._bucket];
}
if (!(_rep.hashnext(element) = *it._pprev))
_rep.first_bucket = 0;
}
*it._pprev = it._element = element;
return old;
}
template <typename T, typename A>
inline void HashContainer<T, A>::insert_at(iterator &it, T *element)
{
click_hash_assert(it._hc == this && it._bucket < _rep.nbuckets);
click_hash_assert(bucket(_rep.hashkey(element)) == it._bucket);
++_rep.size;
if (!(_rep.hashnext(element) = *it._pprev))
_rep.first_bucket = 0;
*it._pprev = element;
it._pprev = &_rep.hashnext(element);
}
template <typename T, typename A>
inline T *HashContainer<T, A>::set(T *element)
{
iterator it = find(_rep.hashkey(element));
return set(it, element);
}
template <typename T, typename A>
inline T *HashContainer<T, A>::erase(iterator &it)
{
click_hash_assert(it._hc == this);
return set(it, 0);
}
template <typename T, typename A>
inline T *HashContainer<T, A>::erase(const key_type &key)
{
iterator it = find(key);
return set(it, 0);
}
template <typename T, typename A>
inline void HashContainer<T, A>::clear()
{
for (bucket_count_type b = 0; b < _rep.nbuckets; ++b)
_rep.buckets[b] = 0;
_rep.size = 0;
}
template <typename T, typename A>
inline void HashContainer<T, A>::swap(HashContainer<T, A> &o)
{
HashContainer_rep<T, A> rep(_rep);
_rep = o._rep;
o._rep = rep;
}
template <typename T, typename A>
void HashContainer<T, A>::rehash(bucket_count_type n)
{
bucket_count_type new_nbuckets = 1;
while (new_nbuckets < n && new_nbuckets < max_bucket_count)
new_nbuckets = ((new_nbuckets + 1) << 1) - 1;
click_hash_assert(new_nbuckets > 0 && new_nbuckets <= max_bucket_count);
if (_rep.nbuckets == new_nbuckets)
return;
T **new_buckets = (T **) CLICK_LALLOC(sizeof(T *) * new_nbuckets);
for (bucket_count_type b = 0; b < new_nbuckets; ++b)
new_buckets[b] = 0;
bucket_count_type old_nbuckets = _rep.nbuckets;
T **old_buckets = _rep.buckets;
_rep.nbuckets = new_nbuckets;
_rep.buckets = new_buckets;
_rep.first_bucket = 0;
_rep.bucket_divider = libdivide_u32_gen(_rep.nbuckets);
click_hash_assert(_rep.nbuckets == libdivide_u32_recover(&_rep.bucket_divider));
for (size_t b = 0; b < old_nbuckets; b++)
for (T *element = old_buckets[b]; element; ) {
T *next = _rep.hashnext(element);
bucket_count_type new_b = bucket(_rep.hashkey(element));
_rep.hashnext(element) = new_buckets[new_b];
new_buckets[new_b] = element;
element = next;
}
CLICK_LFREE(old_buckets, sizeof(T *) * old_nbuckets);
}
template <typename T, typename A>
inline bool
operator==(const HashContainer_const_iterator<T, A> &a, const HashContainer_const_iterator<T, A> &b)
{
click_hash_assert(a.hashcontainer() == b.hashcontainer());
return a.get() == b.get();
}
template <typename T, typename A>
inline bool
operator!=(const HashContainer_const_iterator<T, A> &a, const HashContainer_const_iterator<T, A> &b)
{
click_hash_assert(a.hashcontainer() == b.hashcontainer());
return a.get() != b.get();
}
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,723 @@
/*
* hashmap.{cc,hh} -- a hash table template
* Eddie Kohler
*
* Copyright (c) 2000 Mazu Networks, Inc.
* Copyright (c) 2003 International Computer Science Institute
*
* 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.
*/
#ifndef CLICK_HASHMAP_CC
#define CLICK_HASHMAP_CC
#include <click/hashmap.hh>
#include <click/bighashmap_arena.hh>
#include <click/glue.hh>
CLICK_DECLS
/** @cond never */
#define BIGHASHMAP_REARRANGE_ON_FIND 0
template <class K, class V>
void
HashMap<K, V>::initialize(HashMap_ArenaFactory *factory, size_t initial_nbuckets)
{
_nbuckets = initial_nbuckets;
_buckets = (Elt **) CLICK_LALLOC(_nbuckets * sizeof(Elt *));
for (size_t i = 0; i < _nbuckets; i++)
_buckets[i] = 0;
set_dynamic_resizing(true);
_n = 0;
set_arena(factory);
}
template <class K, class V>
HashMap<K, V>::HashMap()
: _default_value(), _arena(0)
{
initialize(0, DEFAULT_INITIAL_NBUCKETS);
}
template <class K, class V>
HashMap<K, V>::HashMap(const V &def, HashMap_ArenaFactory *factory)
: _default_value(def), _arena(0)
{
initialize(factory, DEFAULT_INITIAL_NBUCKETS);
}
template <class K, class V>
void
HashMap<K, V>::copy_from(const HashMap<K, V> &o)
// requires that 'this' is empty and has the same number of buckets as 'o'
// and the same resize policy
{
for (size_t i = 0; i < _nbuckets; i++) {
Elt **pprev = &_buckets[i];
*pprev = 0;
for (const Elt *e = o._buckets[i]; e; e = e->next) {
Elt *ee = reinterpret_cast<Elt *>(_arena->alloc());
new(reinterpret_cast<void *>(&ee->key)) K(e->key);
new(reinterpret_cast<void *>(&ee->value)) V(e->value);
ee->next = 0;
*pprev = ee;
pprev = &ee->next;
}
}
_n = o._n;
}
template <class K, class V>
HashMap<K, V>::HashMap(const HashMap<K, V> &o)
: _buckets((Elt **) CLICK_LALLOC(o._nbuckets * sizeof(Elt *))),
_nbuckets(o._nbuckets), _default_value(o._default_value),
_capacity(o._capacity), _arena(o._arena)
{
_arena->use();
copy_from(o);
}
template <class K, class V>
HashMap<K, V> &
HashMap<K, V>::operator=(const HashMap<K, V> &o)
{
if (&o != this) {
clear();
_default_value = o._default_value;
if (_nbuckets < o._nbuckets)
resize0(o._nbuckets);
_nbuckets = o._nbuckets;
_capacity = o._capacity;
copy_from(o);
}
return *this;
}
template <class K, class V>
HashMap<K, V>::~HashMap()
{
for (size_t i = 0; i < _nbuckets; i++)
for (Elt *e = _buckets[i]; e; ) {
Elt *next = e->next;
e->key.~K();
e->value.~V();
_arena->free(e);
e = next;
}
CLICK_LFREE(_buckets, _nbuckets * sizeof(Elt *));
_arena->unuse();
}
template <class K, class V>
void
HashMap<K, V>::set_dynamic_resizing(bool on)
{
if (!on)
_capacity = 0x7FFFFFFF;
else if (_nbuckets >= MAX_NBUCKETS)
_capacity = 0x7FFFFFFE;
else
_capacity = DEFAULT_RESIZE_THRESHOLD * _nbuckets;
}
template <class K, class V>
void
HashMap<K, V>::set_arena(HashMap_ArenaFactory *factory)
{
assert(empty());
if (_arena)
_arena->unuse();
_arena = HashMap_ArenaFactory::get_arena(sizeof(Elt), factory);
_arena->use();
}
template <class K, class V>
inline size_t
HashMap<K, V>::bucket(const K &key) const
{
return ((size_t) hashcode(key)) % _nbuckets;
}
template <class K, class V>
typename HashMap<K, V>::Pair *
HashMap<K, V>::find_pair(const K &key) const
{
#if BIGHASHMAP_REARRANGE_ON_FIND
Elt *prev = 0;
size_t b = bucket(key);
for (Elt *e = _buckets[b]; e; prev = e, e = e->next)
if (e->key == key) {
if (prev) {
// move to front
prev->next = e->next;
e->next = _buckets[b];
_buckets[b] = e;
}
return e;
}
return 0;
#else
for (Elt *e = _buckets[bucket(key)]; e; e = e->next)
if (e->key == key)
return e;
return 0;
#endif
}
template <class K, class V>
void
HashMap<K, V>::resize0(size_t new_nbuckets)
{
Elt **new_buckets = (Elt **) CLICK_LALLOC(new_nbuckets * sizeof(Elt *));
for (size_t i = 0; i < new_nbuckets; i++)
new_buckets[i] = 0;
size_t old_nbuckets = _nbuckets;
Elt **old_buckets = _buckets;
_nbuckets = new_nbuckets;
_buckets = new_buckets;
if (dynamic_resizing())
set_dynamic_resizing(true); // reset threshold
for (size_t i = 0; i < old_nbuckets; i++)
for (Elt *e = old_buckets[i]; e; ) {
Elt *n = e->next;
size_t b = bucket(e->key);
e->next = new_buckets[b];
new_buckets[b] = e;
e = n;
}
CLICK_LFREE(old_buckets, old_nbuckets * sizeof(Elt *));
}
template <class K, class V>
void
HashMap<K, V>::resize(size_t want_nbuckets)
{
size_t new_nbuckets = 1;
while (new_nbuckets < want_nbuckets && new_nbuckets < MAX_NBUCKETS)
new_nbuckets = ((new_nbuckets + 1) << 1) - 1;
assert(new_nbuckets > 0 && new_nbuckets <= MAX_NBUCKETS);
if (_nbuckets != new_nbuckets)
resize0(new_nbuckets);
}
template <class K, class V>
bool
HashMap<K, V>::insert(const K &key, const V &value)
{
size_t b = bucket(key);
for (Elt *e = _buckets[b]; e; e = e->next)
if (e->key == key) {
e->value = value;
return false;
}
if (_n >= _capacity) {
resize(_nbuckets + 1);
b = bucket(key);
}
if (Elt *e = reinterpret_cast<Elt *>(_arena->alloc())) {
new(reinterpret_cast<void *>(&e->key)) K(key);
new(reinterpret_cast<void *>(&e->value)) V(value);
e->next = _buckets[b];
_buckets[b] = e;
_n++;
}
return true;
}
template <class K, class V>
bool
HashMap<K, V>::erase(const K &key)
{
size_t b = bucket(key);
Elt *prev = 0;
Elt *e = _buckets[b];
while (e && !(e->key == key)) {
prev = e;
e = e->next;
}
if (e) {
if (prev)
prev->next = e->next;
else
_buckets[b] = e->next;
e->key.~K();
e->value.~V();
_arena->free(e);
_n--;
return true;
} else
return false;
}
template <class K, class V>
typename HashMap<K, V>::Pair *
HashMap<K, V>::find_pair_force(const K &key, const V &default_value)
{
size_t b = bucket(key);
for (Elt *e = _buckets[b]; e; e = e->next)
if (e->key == key)
return e;
if (_n >= _capacity) {
resize(_nbuckets + 1);
b = bucket(key);
}
if (Elt *e = reinterpret_cast<Elt *>(_arena->alloc())) {
new(reinterpret_cast<void *>(&e->key)) K(key);
new(reinterpret_cast<void *>(&e->value)) V(default_value);
e->next = _buckets[b];
_buckets[b] = e;
_n++;
return e;
} else
return 0;
}
template <class K, class V>
void
HashMap<K, V>::clear()
{
for (size_t i = 0; i < _nbuckets; i++) {
for (Elt *e = _buckets[i]; e; ) {
Elt *next = e->next;
e->key.~K();
e->value.~V();
_arena->free(e);
e = next;
}
_buckets[i] = 0;
}
_n = 0;
}
template <class K, class V>
void
HashMap<K, V>::swap(HashMap<K, V> &o)
{
Elt **t_elts;
V t_v;
size_t t_size;
HashMap_Arena *t_arena;
t_elts = _buckets; _buckets = o._buckets; o._buckets = t_elts;
t_size = _nbuckets; _nbuckets = o._nbuckets; o._nbuckets = t_size;
t_v = _default_value; _default_value = o._default_value; o._default_value = t_v;
t_size = _n; _n = o._n; o._n = t_size;
t_size = _capacity; _capacity = o._capacity; o._capacity = t_size;
t_arena = _arena; _arena = o._arena; o._arena = t_arena;
}
template <class K, class V>
_HashMap_const_iterator<K, V>::_HashMap_const_iterator(const HashMap<K, V> *hm, bool begin)
: _hm(hm)
{
size_t nb = _hm->_nbuckets;
typename HashMap<K, V>::Elt **b = _hm->_buckets;
for (_bucket = 0; _bucket < nb && begin; _bucket++)
if (b[_bucket]) {
_elt = b[_bucket];
return;
}
_elt = 0;
}
template <class K, class V>
void
_HashMap_const_iterator<K, V>::operator++(int)
{
if (_elt->next)
_elt = _elt->next;
else {
size_t nb = _hm->_nbuckets;
typename HashMap<K, V>::Elt **b = _hm->_buckets;
for (_bucket++; _bucket < nb; _bucket++)
if (b[_bucket]) {
_elt = b[_bucket];
return;
}
_elt = 0;
}
}
#if 0
static size_t
HashMap_partition_elts(void **elts, size_t left, size_t right)
{
void *pivot = elts[(left + right) / 2];
// loop invariant:
// elts[i] < pivot for all left_init <= i < left
// elts[i] > pivot for all right < i <= right_init
while (left < right) {
if (elts[left] < pivot)
left++;
else if (elts[right] > pivot)
right--;
else {
void *x = elts[left];
elts[left] = elts[right];
elts[right] = x;
}
}
return left;
}
void
HashMap_qsort_elts(void **elts, size_t left, size_t right)
{
if (left < right) {
size_t split = HashMap_partition_elts(elts, left, right);
HashMap_qsort_elts(elts, left, split);
HashMap_qsort_elts(elts, split, right);
}
}
#endif
// void * partial specialization
template <class K>
void
HashMap<K, void *>::initialize(HashMap_ArenaFactory *factory, size_t initial_nbuckets)
{
_nbuckets = initial_nbuckets;
_buckets = (Elt **) CLICK_LALLOC(_nbuckets * sizeof(Elt *));
for (size_t i = 0; i < _nbuckets; i++)
_buckets[i] = 0;
set_dynamic_resizing(true);
_n = 0;
set_arena(factory);
}
template <class K>
HashMap<K, void *>::HashMap()
: _default_value(0), _arena(0)
{
initialize(0, DEFAULT_INITIAL_NBUCKETS);
}
template <class K>
HashMap<K, void *>::HashMap(void *def, HashMap_ArenaFactory *factory)
: _default_value(def), _arena(0)
{
initialize(factory, DEFAULT_INITIAL_NBUCKETS);
}
template <class K>
void
HashMap<K, void *>::copy_from(const HashMap<K, void *> &o)
{
for (size_t i = 0; i < _nbuckets; i++) {
Elt **pprev = &_buckets[i];
*pprev = 0;
for (const Elt *e = o._buckets[i]; e; e = e->next) {
Elt *ee = reinterpret_cast<Elt *>(_arena->alloc());
new(reinterpret_cast<void *>(&ee->key)) K(e->key);
ee->value = e->value;
ee->next = 0;
*pprev = ee;
pprev = &ee->next;
}
}
_n = o._n;
}
template <class K>
HashMap<K, void *>::HashMap(const HashMap<K, void *> &o)
: _buckets((Elt **) CLICK_LALLOC(o._nbuckets * sizeof(Elt *))),
_nbuckets(o._nbuckets), _default_value(o._default_value),
_capacity(o._capacity), _arena(o._arena)
{
_arena->use();
copy_from(o);
}
template <class K>
HashMap<K, void *> &
HashMap<K, void *>::operator=(const HashMap<K, void *> &o)
{
if (&o != this) {
clear();
_default_value = o._default_value;
if (_nbuckets < o._nbuckets)
resize0(o._nbuckets);
_nbuckets = o._nbuckets;
_capacity = o._capacity;
copy_from(o);
}
return *this;
}
template <class K>
HashMap<K, void *>::~HashMap()
{
for (size_t i = 0; i < _nbuckets; i++)
for (Elt *e = _buckets[i]; e; ) {
Elt *next = e->next;
e->key.~K();
_arena->free(e);
e = next;
}
CLICK_LFREE(_buckets, _nbuckets * sizeof(Elt *));
_arena->unuse();
}
template <class K>
void
HashMap<K, void *>::set_dynamic_resizing(bool on)
{
if (!on)
_capacity = 0x7FFFFFFF;
else if (_nbuckets >= MAX_NBUCKETS)
_capacity = 0x7FFFFFFE;
else
_capacity = DEFAULT_RESIZE_THRESHOLD * _nbuckets;
}
template <class K>
void
HashMap<K, void *>::set_arena(HashMap_ArenaFactory *factory)
{
assert(empty());
if (_arena)
_arena->unuse();
_arena = HashMap_ArenaFactory::get_arena(sizeof(Elt), factory);
_arena->use();
}
template <class K>
inline size_t
HashMap<K, void *>::bucket(const K &key) const
{
return ((size_t) hashcode(key)) % _nbuckets;
}
template <class K>
typename HashMap<K, void *>::Pair *
HashMap<K, void *>::find_pair(const K &key) const
{
#if BIGHASHMAP_REARRANGE_ON_FIND
Elt *prev = 0;
size_t b = bucket(key);
for (Elt *e = _buckets[b]; e; prev = e, e = e->next)
if (e->key == key) {
if (prev) {
// move to front
prev->next = e->next;
e->next = _buckets[b];
_buckets[b] = e;
}
return e;
}
return 0;
#else
for (Elt *e = _buckets[bucket(key)]; e; e = e->next)
if (e->key == key)
return e;
return 0;
#endif
}
template <class K>
void
HashMap<K, void *>::resize0(size_t new_nbuckets)
{
Elt **new_buckets = (Elt **) CLICK_LALLOC(new_nbuckets * sizeof(Elt *));
for (size_t i = 0; i < new_nbuckets; i++)
new_buckets[i] = 0;
size_t old_nbuckets = _nbuckets;
Elt **old_buckets = _buckets;
_nbuckets = new_nbuckets;
_buckets = new_buckets;
if (dynamic_resizing())
set_dynamic_resizing(true); // reset threshold
for (size_t i = 0; i < old_nbuckets; i++)
for (Elt *e = old_buckets[i]; e; ) {
Elt *n = e->next;
size_t b = bucket(e->key);
e->next = new_buckets[b];
new_buckets[b] = e;
e = n;
}
CLICK_LFREE(old_buckets, old_nbuckets * sizeof(Elt *));
}
template <class K>
void
HashMap<K, void *>::resize(size_t want_nbuckets)
{
size_t new_nbuckets = 1;
while (new_nbuckets < want_nbuckets && new_nbuckets < MAX_NBUCKETS)
new_nbuckets = ((new_nbuckets + 1) << 1) - 1;
assert(new_nbuckets > 0 && new_nbuckets <= MAX_NBUCKETS);
if (_nbuckets != new_nbuckets)
resize0(new_nbuckets);
}
template <class K>
bool
HashMap<K, void *>::insert(const K &key, void *value)
{
size_t b = bucket(key);
for (Elt *e = _buckets[b]; e; e = e->next)
if (e->key == key) {
e->value = value;
return false;
}
if (_n >= _capacity) {
resize(_nbuckets + 1);
b = bucket(key);
}
if (Elt *e = reinterpret_cast<Elt *>(_arena->alloc())) {
new(reinterpret_cast<void *>(&e->key)) K(key);
e->value = value;
e->next = _buckets[b];
_buckets[b] = e;
_n++;
}
return true;
}
template <class K>
bool
HashMap<K, void *>::erase(const K &key)
{
size_t b = bucket(key);
Elt *prev = 0;
Elt *e = _buckets[b];
while (e && !(e->key == key)) {
prev = e;
e = e->next;
}
if (e) {
if (prev)
prev->next = e->next;
else
_buckets[b] = e->next;
e->key.~K();
_arena->free(e);
_n--;
return true;
} else
return false;
}
template <class K>
typename HashMap<K, void *>::Pair *
HashMap<K, void *>::find_pair_force(const K &key, void *default_value)
{
size_t b = bucket(key);
for (Elt *e = _buckets[b]; e; e = e->next)
if (e->key == key)
return e;
if (_n >= _capacity) {
resize(_nbuckets + 1);
b = bucket(key);
}
if (Elt *e = reinterpret_cast<Elt *>(_arena->alloc())) {
new(reinterpret_cast<void *>(&e->key)) K(key);
e->value = default_value;
e->next = _buckets[b];
_buckets[b] = e;
_n++;
return e;
} else
return 0;
}
template <class K>
void
HashMap<K, void *>::clear()
{
for (size_t i = 0; i < _nbuckets; i++) {
for (Elt *e = _buckets[i]; e; ) {
Elt *next = e->next;
e->key.~K();
_arena->free(e);
e = next;
}
_buckets[i] = 0;
}
_n = 0;
}
template <class K>
void
HashMap<K, void *>::swap(HashMap<K, void *> &o)
{
Elt **t_elts;
void *t_v;
size_t t_size;
HashMap_Arena *t_arena;
t_elts = _buckets; _buckets = o._buckets; o._buckets = t_elts;
t_size = _nbuckets; _nbuckets = o._nbuckets; o._nbuckets = t_size;
t_v = _default_value; _default_value = o._default_value; o._default_value = t_v;
t_size = _n; _n = o._n; o._n = t_size;
t_size = _capacity; _capacity = o._capacity; o._capacity = t_size;
t_arena = _arena; _arena = o._arena; o._arena = t_arena;
}
template <class K>
_HashMap_const_iterator<K, void *>::_HashMap_const_iterator(const HashMap<K, void *> *hm, bool begin)
: _hm(hm)
{
size_t nb = _hm->_nbuckets;
typename HashMap<K, void *>::Elt **b = _hm->_buckets;
for (_bucket = 0; _bucket < nb && begin; _bucket++)
if (b[_bucket]) {
_elt = b[_bucket];
return;
}
_elt = 0;
}
template <class K>
void
_HashMap_const_iterator<K, void *>::operator++(int)
{
if (_elt->next)
_elt = _elt->next;
else {
size_t nb = _hm->_nbuckets;
typename HashMap<K, void *>::Elt **b = _hm->_buckets;
for (_bucket++; _bucket < nb; _bucket++)
if (b[_bucket]) {
_elt = b[_bucket];
return;
}
_elt = 0;
}
}
/** @endcond */
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,585 @@
#ifndef CLICK_HASHMAP_HH
#define CLICK_HASHMAP_HH
#include <click/hashcode.hh>
CLICK_DECLS
/** @cond never */
class HashMap_Arena;
class HashMap_ArenaFactory;
// K AND V REQUIREMENTS:
//
// K::K(const K &)
// k1 == k2
// hashcode_t hashcode(const K &)
// If hashcode(k1) != hashcode(k2), then k1 != k2.
// hashcode() can return any unsigned value.
//
// V::V() -- only used for default value
// V::V(const V &)
// V & V::operator=(const V &)
template <class K, class V = void> class _HashMap_const_iterator;
template <class K, class V = void> class _HashMap_iterator;
template <class K, class V = void> class HashMap;
template <class K, class V>
class HashMap { public:
typedef K key_type;
typedef V mapped_type;
struct Pair;
HashMap();
explicit HashMap(const V &, HashMap_ArenaFactory * = 0);
HashMap(const HashMap<K, V> &);
~HashMap();
void set_arena(HashMap_ArenaFactory *);
size_t size() const { return _n; }
bool empty() const { return _n == 0; }
size_t nbuckets() const { return _nbuckets; }
Pair *find_pair(const K &) const;
inline V *findp(const K &) const;
inline const V &find(const K &, const V &) const;
inline const V &find(const K &) const;
inline const V &operator[](const K &) const;
Pair *find_pair_force(const K &, const V &);
Pair *find_pair_force(const K &k) { return find_pair_force(k, _default_value); }
V *findp_force(const K &k, const V &v) { if (Pair *p = find_pair_force(k, v)) return &p->value; else return 0; }
V &find_force(const K &k, const V &v) { return *findp_force(k, v); }
V *findp_force(const K &k) { return findp_force(k, _default_value); }
V &find_force(const K &k) { return *findp_force(k, _default_value); }
bool insert(const K &, const V &);
bool erase(const K &);
bool remove(const K &key) {
return erase(key);
}
void clear();
void swap(HashMap<K, V> &);
// iteration
typedef _HashMap_const_iterator<K, V> const_iterator;
typedef _HashMap_iterator<K, V> iterator;
inline const_iterator begin() const;
inline iterator begin();
inline const_iterator end() const;
inline iterator end();
// dynamic resizing
void resize(size_t);
bool dynamic_resizing() const { return _capacity < 0x7FFFFFFF; }
void set_dynamic_resizing(bool);
HashMap<K, V> &operator=(const HashMap<K, V> &);
struct Pair {
K key;
V value;
};
enum { MAX_NBUCKETS = 4194303,
DEFAULT_INITIAL_NBUCKETS = 127,
DEFAULT_RESIZE_THRESHOLD = 2 };
private:
struct Elt : public Pair {
Elt *next;
#if defined(__GNUC__) && __GNUC__ < 4
/* Shut up compiler about Pair lacking default constructor */
Elt(const Pair &p) : Pair(p) { }
#endif
};
Elt **_buckets;
size_t _nbuckets;
V _default_value;
size_t _n;
size_t _capacity;
HashMap_Arena *_arena;
void initialize(HashMap_ArenaFactory *, size_t);
void copy_from(const HashMap<K, V> &);
void resize0(size_t);
size_t bucket(const K &) const;
friend class _HashMap_iterator<K, V>;
friend class _HashMap_const_iterator<K, V>;
};
template <class K, class V>
class _HashMap_const_iterator { public:
bool live() const { return _elt; }
typedef bool (_HashMap_const_iterator::*unspecified_bool_type)() const;
inline operator unspecified_bool_type() const CLICK_DEPRECATED;
void operator++(int);
void operator++() { (*this)++; }
typedef typename HashMap<K, V>::Pair Pair;
const Pair *pair() const { return _elt; }
const K &key() const { return _elt->key; }
const V &value() const { return _elt->value; }
private:
const HashMap<K, V> *_hm;
typename HashMap<K, V>::Elt *_elt;
size_t _bucket;
_HashMap_const_iterator(const HashMap<K, V> *m, bool begin);
friend class HashMap<K, V>;
friend class _HashMap_iterator<K, V>;
};
template <class K, class V>
class _HashMap_iterator : public _HashMap_const_iterator<K, V> { public:
typedef _HashMap_const_iterator<K, V> inherited;
typedef typename HashMap<K, V>::Pair Pair;
Pair *pair() const { return const_cast<Pair *>(inherited::pair()); }
V &value() const { return const_cast<V &>(inherited::value()); }
private:
_HashMap_iterator(HashMap<K, V> *m, bool begin) : inherited(m, begin) { }
friend class HashMap<K, V>;
};
template <class K, class V>
inline typename HashMap<K, V>::const_iterator
HashMap<K, V>::begin() const
{
return const_iterator(this, true);
}
template <class K, class V>
inline typename HashMap<K, V>::iterator
HashMap<K, V>::begin()
{
return iterator(this, true);
}
template <class K, class V>
inline typename HashMap<K, V>::const_iterator
HashMap<K, V>::end() const
{
return const_iterator(this, false);
}
template <class K, class V>
inline typename HashMap<K, V>::iterator
HashMap<K, V>::end()
{
return iterator(this, false);
}
template <class K, class V>
inline V *
HashMap<K, V>::findp(const K &key) const
{
Pair *p = find_pair(key);
return (p ? &p->value : 0);
}
template <class K, class V>
inline const V &
HashMap<K, V>::find(const K &key, const V &default_value) const
{
Pair *p = find_pair(key);
const V *v = (p ? &p->value : &default_value);
return *v;
}
template <class K, class V>
inline const V &
HashMap<K, V>::find(const K &key) const
{
return find(key, _default_value);
}
template <class K, class V>
inline const V &
HashMap<K, V>::operator[](const K &key) const
{
return find(key);
}
template <class K, class V>
inline
_HashMap_const_iterator<K, V>::operator unspecified_bool_type() const
{
return live() ? &_HashMap_const_iterator::live : 0;
}
template <class K>
class HashMap<K, void *> { public:
typedef K key_type;
typedef void *mapped_type;
struct Pair;
HashMap();
explicit HashMap(void *, HashMap_ArenaFactory * = 0);
HashMap(const HashMap<K, void *> &);
~HashMap();
void set_arena(HashMap_ArenaFactory *);
size_t size() const { return _n; }
bool empty() const { return _n == 0; }
size_t nbuckets() const { return _nbuckets; }
Pair *find_pair(const K &) const;
inline void **findp(const K &) const;
inline void *find(const K &, void *) const;
inline void *find(const K &) const;
inline void *operator[](const K &) const;
Pair *find_pair_force(const K &, void *);
Pair *find_pair_force(const K &k) { return find_pair_force(k, _default_value); }
void **findp_force(const K &k, void *v) { if (Pair *p = find_pair_force(k, v)) return &p->value; else return 0; }
void *&find_force(const K &k, void *v) { return *findp_force(k, v); }
void **findp_force(const K &k) { return findp_force(k, _default_value); }
void *&find_force(const K &k) { return *findp_force(k, _default_value); }
bool insert(const K &, void *);
bool erase(const K &);
bool remove(const K &key) {
return erase(key);
}
void clear();
void swap(HashMap<K, void *> &);
// iterators
typedef _HashMap_const_iterator<K, void *> const_iterator;
typedef _HashMap_iterator<K, void *> iterator;
inline const_iterator begin() const;
inline iterator begin();
inline const_iterator end() const;
inline iterator end();
// dynamic resizing
void resize(size_t);
bool dynamic_resizing() const { return _capacity < 0x7FFFFFFF; }
void set_dynamic_resizing(bool);
HashMap<K, void *> &operator=(const HashMap<K, void *> &);
struct Pair {
K key;
void *value;
};
enum { MAX_NBUCKETS = 32767,
DEFAULT_INITIAL_NBUCKETS = 127,
DEFAULT_RESIZE_THRESHOLD = 2 };
private:
struct Elt : public Pair {
Elt *next;
#if defined(__GNUC__) && __GNUC__ < 4
/* Shut up compiler about Pair lacking default constructor */
Elt(const Pair &p) : Pair(p) { }
#endif
};
Elt **_buckets;
size_t _nbuckets;
void *_default_value;
size_t _n;
size_t _capacity;
HashMap_Arena *_arena;
void initialize(HashMap_ArenaFactory *, size_t);
void copy_from(const HashMap<K, void *> &);
void resize0(size_t);
size_t bucket(const K &) const;
friend class _HashMap_iterator<K, void *>;
friend class _HashMap_const_iterator<K, void *>;
};
template <class K>
class _HashMap_const_iterator<K, void *> { public:
bool live() const { return _elt; }
typedef bool (_HashMap_const_iterator::*unspecified_bool_type)() const;
inline operator unspecified_bool_type() const CLICK_DEPRECATED;
void operator++(int);
void operator++() { (*this)++; }
typedef typename HashMap<K, void *>::Pair Pair;
const Pair *pair() const { return _elt; }
const K &key() const { return _elt->key; }
void *value() const { return _elt->value; }
private:
const HashMap<K, void *> *_hm;
typename HashMap<K, void *>::Elt *_elt;
size_t _bucket;
_HashMap_const_iterator(const HashMap<K, void *> *, bool begin);
template <class, class> friend class _HashMap_const_iterator;
template <class, class> friend class _HashMap_iterator;
template <class, class> friend class HashMap;
};
template <class K>
class _HashMap_iterator<K, void *> : public _HashMap_const_iterator<K, void *> { public:
typedef _HashMap_const_iterator<K, void *> inherited;
typedef typename HashMap<K, void *>::Pair Pair;
Pair *pair() const { return const_cast<Pair *>(inherited::pair()); }
void *&value() const { return this->_elt->value; }
private:
_HashMap_iterator(HashMap<K, void *> *m, bool begin) : inherited(m, begin) { }
template <class, class> friend class HashMap;
};
template <class K>
inline typename HashMap<K, void *>::const_iterator
HashMap<K, void *>::begin() const
{
return const_iterator(this, true);
}
template <class K>
inline typename HashMap<K, void *>::iterator
HashMap<K, void *>::begin()
{
return iterator(this, true);
}
template <class K>
inline typename HashMap<K, void *>::const_iterator
HashMap<K, void *>::end() const
{
return const_iterator(this, false);
}
template <class K>
inline typename HashMap<K, void *>::iterator
HashMap<K, void *>::end()
{
return iterator(this, false);
}
template <class K>
inline void **
HashMap<K, void *>::findp(const K &key) const
{
Pair *p = find_pair(key);
return (p ? &p->value : 0);
}
template <class K>
inline void *
HashMap<K, void *>::find(const K &key, void *default_value) const
{
Pair *p = find_pair(key);
return (p ? p->value : default_value);
}
template <class K>
inline void *
HashMap<K, void *>::find(const K &key) const
{
return find(key, _default_value);
}
template <class K>
inline void *
HashMap<K, void *>::operator[](const K &key) const
{
return find(key);
}
template <class K>
inline
_HashMap_const_iterator<K, void *>::operator unspecified_bool_type() const
{
return live() ? &_HashMap_const_iterator::live : 0;
}
template <class K, class T>
class HashMap<K, T *> : public HashMap<K, void *> { public:
typedef K key_type;
typedef T *mapped_type;
typedef HashMap<K, void *> inherited;
struct Pair;
HashMap() : inherited() { }
explicit HashMap(T *def, HashMap_ArenaFactory *factory = 0)
: inherited(def, factory) { }
HashMap(const HashMap<K, T *> &o) : inherited(o) { }
~HashMap() { }
void set_arena(HashMap_ArenaFactory *af) { inherited::set_arena(af); }
// size_t size() const inherited
// bool empty() const inherited
// size_t nbuckets() const inherited
Pair *find_pair(const K &k) const { return reinterpret_cast<Pair *>(inherited::find_pair(k)); }
T **findp(const K &k) const { return reinterpret_cast<T **>(inherited::findp(k)); }
T *find(const K &k, T *v) const { return reinterpret_cast<T *>(inherited::find(k, v)); }
T *find(const K &k) const { return reinterpret_cast<T *>(inherited::find(k)); }
T *operator[](const K &k) const { return reinterpret_cast<T *>(inherited::operator[](k)); }
Pair *find_pair_force(const K &k, T *v) { return reinterpret_cast<Pair *>(inherited::find_pair_force(k, v)); }
Pair *find_pair_force(const K &k) { return reinterpret_cast<Pair *>(inherited::find_pair_force(k)); }
T **findp_force(const K &k, T *v) { return reinterpret_cast<T **>(inherited::findp_force(k, v)); }
T *&find_force(const K &k, T *v) { return *reinterpret_cast<T **>(inherited::findp_force(k, v)); }
T **findp_force(const K &k) { return reinterpret_cast<T **>(inherited::findp_force(k)); }
T *&find_force(const K &k) { return *reinterpret_cast<T **>(inherited::findp_force(k)); }
bool insert(const K &k, T *v) { return inherited::insert(k, v); }
// bool erase(const K &) inherited
// bool remove(const K &) inherited
// void clear() inherited
void swap(HashMap<K, T *> &o) { inherited::swap(o); }
// iteration
typedef _HashMap_const_iterator<K, T *> const_iterator;
typedef _HashMap_iterator<K, T *> iterator;
inline const_iterator begin() const;
inline iterator begin();
inline const_iterator end() const;
inline iterator end();
// dynamic resizing methods inherited
HashMap<K, T *> &operator=(const HashMap<K, T *> &o) { return static_cast<HashMap<K, T *> &>(inherited::operator=(o)); }
struct Pair {
K key;
T *value;
};
};
template <class K, class T>
class _HashMap_const_iterator<K, T *> { public:
typedef _HashMap_const_iterator<K, void *> inherited;
bool live() const { return _i.live(); }
typedef typename inherited::unspecified_bool_type unspecified_bool_type;
inline operator unspecified_bool_type() const CLICK_DEPRECATED;
void operator++(int) { _i.operator++(0); }
void operator++() { _i.operator++(); }
typedef typename HashMap<K, T *>::Pair Pair;
const Pair *pair() const { return reinterpret_cast<const Pair *>(_i.pair()); }
const K &key() const { return _i.key(); }
T *value() const { return reinterpret_cast<T *>(_i.value()); }
private:
inherited _i;
_HashMap_const_iterator(const HashMap<K, T *> *t, bool begin) : _i(t, begin) { }
friend class _HashMap_iterator<K, T *>;
template <class, class> friend class HashMap;
};
template <class K, class T>
class _HashMap_iterator<K, T *> : public _HashMap_const_iterator<K, T *> { public:
typedef _HashMap_const_iterator<K, T *> inherited;
typedef typename HashMap<K, T *>::Pair Pair;
Pair *pair() const { return const_cast<Pair *>(inherited::pair()); }
T *&value() const { return pair()->value; }
private:
_HashMap_iterator(HashMap<K, T *> *t, bool begin) : inherited(t, begin) { }
template <class, class> friend class HashMap;
};
template <class K, class T>
inline typename HashMap<K, T *>::const_iterator
HashMap<K, T *>::begin() const
{
return const_iterator(this, true);
}
template <class K, class T>
inline typename HashMap<K, T *>::iterator
HashMap<K, T *>::begin()
{
return iterator(this, true);
}
template <class K, class T>
inline typename HashMap<K, T *>::const_iterator
HashMap<K, T *>::end() const
{
return const_iterator(this, false);
}
template <class K, class T>
inline typename HashMap<K, T *>::iterator
HashMap<K, T *>::end()
{
return iterator(this, false);
}
template <class K, class T>
inline
_HashMap_const_iterator<K, T *>::operator unspecified_bool_type() const
{
return inherited::live() ? &inherited::live : 0;
}
template <class K, class V>
inline bool
operator==(const _HashMap_const_iterator<K, V> &a, const _HashMap_const_iterator<K, V> &b)
{
return a.pair() == b.pair();
}
template <class K, class V>
inline bool
operator!=(const _HashMap_const_iterator<K, V> &a, const _HashMap_const_iterator<K, V> &b)
{
return a.pair() != b.pair();
}
/** @endcond */
CLICK_ENDDECLS
#include <click/hashmap.cc>
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,425 @@
#ifndef CLICK_HEAP_HH
#define CLICK_HEAP_HH
#include <click/algorithm.hh>
CLICK_DECLS
/** @brief Add an element to a heap.
* @param begin begin random-access iterator
* @param end end random-access iterator
* @param comp compare function object, such as less<>
* @param place placement function object, defaults to do_nothing<>
* @pre @a begin \< @a end
* @pre [@a begin, @a end - 1) is a heap
* @post [@a begin, @a end) is a heap
*
* This function rearranges the elements in [@a begin, @a end) to be a heap.
* It assumes that most of the sequence is already a heap -- only the new
* element, @a end[-1], might not be in a valid place.
*
* The comparison function @a comp defines the heap order.
*
* The placement function @a place is called for each element that
* changes place within the heap order; its arguments are @a begin and
* an iterator for the element that switched place. @a place is always
* called once with an iterator pointing the new element in its final
* place. @a place is useful when elements need to keep track of
* their own positions in the heap order. @a place defaults to
* do_nothing<>().
*
* @sa change_heap, pop_heap, remove_heap */
template <typename iterator_type, typename compare_type, typename place_type>
inline void push_heap(iterator_type begin, iterator_type end,
compare_type comp, place_type place)
{
assert(begin < end);
size_t i = end - begin - 1, npos;
while (i > 0 && (npos = (i-1)/2, comp(begin[i], begin[npos]))) {
click_swap(begin[i], begin[npos]);
place(begin, begin + i);
i = npos;
}
place(begin, begin + i);
}
/** @overload */
template <typename iterator_type, typename compare_type>
inline void push_heap(iterator_type begin, iterator_type end,
compare_type comp)
{
push_heap(begin, end, comp, do_nothing<iterator_type, iterator_type>());
}
/** @brief Change an element's position within a heap.
* @param begin begin random-access iterator
* @param end end random-access iterator
* @param element iterator pointing to element whose position may change
* @param comp compare function object, such as less<>
* @param place placement function object, defaults to do_nothing<>
* @pre @a begin \<= @a element < @a end
* @pre [@a begin, @a end) is a heap, perhaps excluding @a element
* @post [@a begin, @a end) is a heap
* @return iterator pointing to the new location of *@a element
*
* This function rearranges the elements in [@a begin, @a end) to be a heap.
* It assumes that most of the sequence is already a heap. Only the element
* pointed to by @a element might be out of place.
*
* The comparison function @a comp defines the heap order.
*
* The placement function @a place is called for each element that
* changes place within the heap order; its arguments are @a begin and
* an iterator for the element that switched place. @a place is
* useful when elements need to keep track of their own positions in
* the heap order. @a place defaults to do_nothing<>().
*
* @sa push_heap, pop_heap, remove_heap */
template <typename iterator_type, typename compare_type, typename place_type>
iterator_type change_heap(iterator_type begin, iterator_type end,
iterator_type element,
compare_type comp, place_type place)
{
assert(begin <= element && element < end);
size_t i = element - begin, size = end - begin, npos;
while (i > 0 && (npos = (i-1)/2, comp(begin[i], begin[npos]))) {
click_swap(begin[i], begin[npos]);
place(begin, begin + i);
i = npos;
}
while (1) {
size_t smallest = i, trial = i*2 + 1;
if (trial < size && comp(begin[trial], begin[smallest]))
smallest = trial;
if (trial + 1 < size && comp(begin[trial + 1], begin[smallest]))
smallest = trial + 1;
if (smallest == i)
break;
click_swap(begin[i], begin[smallest]);
place(begin, begin + i);
i = smallest;
}
if (begin + i != element)
place(begin, begin + i);
return begin + i;
}
/** @overload */
template <typename iterator_type, typename compare_type>
inline iterator_type change_heap(iterator_type begin, iterator_type end,
iterator_type element, compare_type comp)
{
return change_heap(begin, end, element, comp, do_nothing<iterator_type, iterator_type>());
}
/** @brief Remove an element from a heap.
* @param begin begin random-access iterator
* @param end end random-access iterator
* @param element iterator pointing to element to remove
* @param comp compare function object, such as less<>
* @param place placement function object, defaults to do_nothing<>
* @pre @a begin \<= @a element < @a end
* @pre [@a begin, @a end) is a heap, possibly excluding @a element
* @post [@a begin, @a end - 1) is a heap, and the element formerly at
* *@a element has shifted to *(@a end - 1)
*
* This function removes @a element from the heap in [@a begin, @a end) by
* shifting it to the end, preserving the heap property on the remaining
* elements.
*
* The comparison function @a comp defines the heap order.
*
* The placement function @a place is called for each actual element
* that changes place within the heap order; its arguments are @a
* begin and an iterator for the element that switched place. It is
* not called on @a element, which is no longer considered a member of
* the heap. @a place is useful when elements need to keep track of
* their own positions in the heap order. @a place defaults to
* do_nothing<>().
*
* @sa push_heap, change_heap, pop_heap */
template <typename iterator_type, typename compare_type, typename place_type>
inline void remove_heap(iterator_type begin, iterator_type end,
iterator_type element,
compare_type comp, place_type place)
{
assert(begin <= element && element < end);
if (element + 1 != end) {
click_swap(element[0], end[-1]);
place(begin, element);
change_heap(begin, end - 1, element, comp, place);
}
}
/** @overload */
template <typename iterator_type, typename compare_type>
inline void remove_heap(iterator_type begin, iterator_type end,
iterator_type element,
compare_type comp)
{
remove_heap(begin, end, element, comp, do_nothing<iterator_type, iterator_type>());
}
/** @brief Remove the first element from a heap.
* @param begin begin random-access iterator
* @param end end random-access iterator
* @param comp compare function object, such as less<>
* @param place placement function object, defaults to do_nothing<>
* @pre @a begin \< @a end
* @pre [@a begin, @a end) is a heap
* @post [@a begin, @a end - 1) is a heap, and the element formerly at
* *@a begin has shifted to *(@a end - 1)
*
* This function removes the first element of [@a begin, @a end) from a heap
* by shifting it to the end, preserving the heap property on the remaining
* elements.
*
* The comparison function @a comp defines the heap order.
*
* The placement function @a place is called for each element that
* changes place within the heap order; its arguments are @a begin and
* an iterator for the element that switched place. It is not called
* on the first element, which is no longer considered a member of the
* heap. @a place is useful when elements need to keep track of their
* own positions in the heap order. @a place defaults to
* do_nothing<>().
*
* @sa push_heap, change_heap, remove_heap */
template <typename iterator_type, typename compare_type, typename place_type>
inline void pop_heap(iterator_type begin, iterator_type end,
compare_type comp, place_type place)
{
remove_heap(begin, end, begin, comp, place);
}
/** @overload */
template <typename iterator_type, typename compare_type>
inline void pop_heap(iterator_type begin, iterator_type end,
compare_type comp)
{
pop_heap(begin, end, comp, do_nothing<iterator_type, iterator_type>());
}
/** @brief Add an element to a d-ary heap.
* @param begin begin random-access iterator
* @param end end random-access iterator
* @param comp compare function object, such as less<>
* @param place placement function object, defaults to do_nothing<>
* @pre @a begin \< @a end
* @pre [@a begin, @a end - 1) is a d-ary heap
* @post [@a begin, @a end) is a d-ary heap
*
* This function rearranges the elements in [@a begin, @a end) to be
* a d-ary heap. It assumes that most of the sequence is already a
* heap -- only the new element, @a end[-1], might not be in a valid
* place. The arity @a n is a template parameter, and must be greater
* than 2.
*
* The comparison function @a comp defines the heap order.
*
* The placement function @a place is called for each element that
* changes place within the heap order; its arguments are @a begin and
* an iterator for the element that switched place. @a place is always
* called once with an iterator pointing the new element in its final
* place. @a place is useful when elements need to keep track of
* their own positions in the heap order. @a place defaults to
* do_nothing<>().
*
* @sa change_heap, pop_heap, remove_heap */
template <int arity,
typename iterator_type, typename compare_type, typename place_type>
inline void push_heap(iterator_type begin, iterator_type end,
compare_type comp, place_type place)
{
static_assert(arity > 2, "For arity == 2, use push_heap(...), not push_heap<2>(...).");
assert(begin < end);
size_t i = end - begin - 1, npos;
while (i > 0 && (npos = i/arity, comp(begin[i], begin[npos]))) {
click_swap(begin[i], begin[npos]);
place(begin, begin + i);
i = npos;
}
place(begin, begin + i);
}
/** @overload */
template <int arity, typename iterator_type, typename compare_type>
inline void push_heap(iterator_type begin, iterator_type end,
compare_type comp)
{
push_heap<arity>(begin, end, comp, do_nothing<iterator_type, iterator_type>());
}
/** @brief Change an element's position within a d-ary heap.
* @param begin begin random-access iterator
* @param end end random-access iterator
* @param element iterator pointing to element whose position may change
* @param comp compare function object, such as less<>
* @param place placement function object, defaults to do_nothing<>
* @pre @a begin \<= @a element < @a end
* @pre [@a begin, @a end) is a d-ary heap, perhaps excluding @a element
* @post [@a begin, @a end) is a d-ary heap
* @return iterator pointing to the new location of *@a element
*
* This function rearranges the elements in [@a begin, @a end) to be
* a d-ary heap. It assumes that most of the sequence is already a
* heap. Only the element pointed to by @a element might be out of
* place. The arity @a n is a template parameter, and must be greater
* than 2.
*
* The comparison function @a comp defines the heap order.
*
* The placement function @a place is called for each element that
* changes place within the heap order; its arguments are @a begin and
* an iterator for the element that switched place. @a place is
* useful when elements need to keep track of their own positions in
* the heap order. @a place defaults to do_nothing<>().
*
* @sa push_heap, pop_heap, remove_heap */
template <int arity,
typename iterator_type, typename compare_type, typename place_type>
iterator_type change_heap(iterator_type begin, iterator_type end,
iterator_type element,
compare_type comp, place_type place)
{
static_assert(arity > 2, "For arity == 2, use change_heap(...), not change_heap<2>(...).");
assert(begin <= element && element < end);
size_t i = element - begin, size = end - begin, npos;
while (i > 0 && (npos = i/arity, comp(begin[i], begin[npos]))) {
click_swap(begin[i], begin[npos]);
place(begin, begin + i);
i = npos;
}
while (1) {
size_t smallest = i,
trial = i ? i * arity : 1,
end_trial = i ? trial + arity : arity;
end_trial = end_trial < size ? end_trial : size;
for (; trial < end_trial; ++trial)
if (comp(begin[trial], begin[smallest]))
smallest = trial;
if (smallest == i)
break;
click_swap(begin[i], begin[smallest]);
place(begin, begin + i);
i = smallest;
}
if (begin + i != element)
place(begin, begin + i);
return begin + i;
}
/** @overload */
template <int arity,
typename iterator_type, typename compare_type>
inline iterator_type change_heap(iterator_type begin, iterator_type end,
iterator_type element, compare_type comp)
{
return change_heap<arity>(begin, end, element, comp, do_nothing<iterator_type, iterator_type>());
}
/** @brief Remove an element from a d-ary heap.
* @param begin begin random-access iterator
* @param end end random-access iterator
* @param element iterator pointing to element to remove
* @param comp compare function object, such as less<>
* @param place placement function object, defaults to do_nothing<>
* @pre @a begin \<= @a element < @a end
* @pre [@a begin, @a end) is a d-ary heap, possibly excluding @a element
* @post [@a begin, @a end - 1) is a d-ary heap, and the element formerly
* at *@a element has shifted to *(@a end - 1)
*
* This function removes @a element from the d-ary heap in [@a begin,
* @a end) by shifting it to the end, preserving the heap property on
* the remaining elements. The arity @a n is a template parameter.
*
* The comparison function @a comp defines the heap order.
*
* The placement function @a place is called for each actual element
* that changes place within the heap order; its arguments are @a
* begin and an iterator for the element that switched place. It is
* not called on @a element, which is no longer considered a member of
* the heap. @a place is useful when elements need to keep track of
* their own positions in the heap order. @a place defaults to
* do_nothing<>().
*
* @sa push_heap, change_heap, pop_heap */
template <int arity,
typename iterator_type, typename compare_type, typename place_type>
inline void remove_heap(iterator_type begin, iterator_type end,
iterator_type element,
compare_type comp, place_type place)
{
assert(begin <= element && element < end);
if (element + 1 != end) {
click_swap(element[0], end[-1]);
place(begin, element);
change_heap<arity>(begin, end - 1, element, comp, place);
}
}
/** @overload */
template <int arity,
typename iterator_type, typename compare_type>
inline void remove_heap(iterator_type begin, iterator_type end,
iterator_type element,
compare_type comp)
{
remove_heap<arity>(begin, end, element, comp, do_nothing<iterator_type, iterator_type>());
}
/** @brief Remove the first element from a d-ary heap.
* @param begin begin random-access iterator
* @param end end random-access iterator
* @param comp compare function object, such as less<>
* @param place placement function object, defaults to do_nothing<>
* @pre @a begin \< @a end
* @pre [@a begin, @a end) is a d-ary heap
* @post [@a begin, @a end - 1) is a d-ary heap, and the element formerly
* at *@a begin has shifted to *(@a end - 1)
*
* This function removes the first element of [@a begin, @a end) from
* a d-ary heap by shifting it to the end, preserving the heap
* property on the remaining elements. The arity @a n is a template
* parameter.
*
* The comparison function @a comp defines the heap order.
*
* The placement function @a place is called for each element that
* changes place within the heap order; its arguments are @a begin and
* an iterator for the element that switched place. It is not called
* on the first element, which is no longer considered a member of the
* heap. @a place is useful when elements need to keep track of their
* own positions in the heap order. @a place defaults to
* do_nothing<>().
*
* @sa push_heap, change_heap, remove_heap */
template <int arity,
typename iterator_type, typename compare_type, typename place_type>
inline void pop_heap(iterator_type begin, iterator_type end,
compare_type comp, place_type place)
{
remove_heap<arity>(begin, end, begin, comp, place);
}
/** @overload */
template <int arity,
typename iterator_type, typename compare_type>
inline void pop_heap(iterator_type begin, iterator_type end,
compare_type comp)
{
pop_heap<arity>(begin, end, comp, do_nothing<iterator_type, iterator_type>());
}
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,133 @@
// -*- c-basic-offset: 4; related-file-name: "../../lib/ino.cc" -*-
#ifndef CLICK_INO_HH
#define CLICK_INO_HH
#include <click/router.hh>
CLICK_DECLS
#define INO_DEBUG 0
// /click: .e > .h > element names > global handlers [dt_global]
// /click/.e: element numbers [dt_u]
// /click/.e/NUM: handlers [dt_hu]
// /click/.h: global handlers [dt_hh]
// /click/ELEMENTNAME: .h > element names > element handlers [dt_hn]
// /click/ELEMENTNAME/.h: element handlers [dt_hh]
class ClickIno { public:
void initialize();
void cleanup();
uint32_t generation() const { return _generation; }
// NB: inode number 0 is reserved for the system.
enum { dt_u = 1U, dt_hh = 2U, dt_hu = 3U, dt_hn = 4U, dt_global = 5U };
enum { ino_globaldir = (unsigned) (dt_global << 28),
ino_enumdir = (unsigned) (dt_u << 28) };
static bool is_handler(unsigned ino) { return (int32_t) ino < 0; }
static unsigned dirtype(unsigned ino) { return ino >> 28; }
static bool has_element(unsigned ino) { return ino & 0xFFFFU; }
static bool has_handlers(unsigned ino) { return ino > (dt_u << 28); }
static bool has_names(unsigned ino) { return ino >= (dt_hn << 28); }
static int ino_element(unsigned ino) { return (int) (ino & 0xFFFFU) - 1; }
static int ino_handler(unsigned ino) {
return (has_element(ino) ? 0 : Router::FIRST_GLOBAL_HANDLER)
+ ((ino >> 16) & 0x7FFFU);
}
static unsigned make_handler(int e, int hi) {
return 0x80000000U | ((hi & 0x7FFFU) << 16) | ((e + 1) & 0xFFFFU);
}
static unsigned make_dir(unsigned dtype, int e) {
return (dtype << 28) | ((e + 1) & 0xFFFFU);
}
// These operations should be called with a configuration lock held.
inline int prepare(Router *router, uint32_t generation);
int nlink(ino_t ino);
ino_t lookup(ino_t dir, const String &component);
// readdir handles '..' (f_pos 0) and '.' (f_pos 1).
// It returns the number of things stored.
typedef bool (*filldir_t)(const char *name, int name_len, ino_t ino, int dirtype, loff_t f_pos, void *user_data);
int readdir(ino_t dir, loff_t &f_pos, filldir_t fd, void *user_data);
#if INO_DEBUG
String info() const;
#endif
struct Entry {
// Name of this entry.
String name;
// Corresponding eindex plus 1. Might be larger than the number of
// elements in the router, because of fake directories added for
// compound "elements".
uint16_t elementno_plus1;
// '_x[i].xindex' equals the index in _x of the entry for element
// number 'i - 1'.
uint16_t xindex;
// Number of child entries. 'name' is guaranteed to be a prefix of
// every child entry.
uint16_t skip;
// See enum below. X_FAKE is true on fake directories added for
// compound elements.
uint16_t flags;
};
private:
enum { X_FAKE = 1 };
Entry* _x;
int _nentries;
int _cap;
Router* _router;
uint32_t _generation;
inline int xindex(int elementno) const;
inline int next_xindex(int elementno) const;
inline int elementno(int xindex) const;
int name_search(const String &n, int first_xi, int last_xi, int name_offset) const;
int element_name_search(const String &n, int elementno) const;
int grow(int min_size);
int true_prepare(Router*, uint32_t);
};
inline int
ClickIno::prepare(Router* router, uint32_t generation)
{
if (generation != _generation)
return true_prepare(router, generation);
else
return 0;
}
inline int
ClickIno::xindex(int elementno) const
{
assert(elementno >= -1 && elementno < _nentries - 1);
return _x[elementno + 1].xindex;
}
inline int
ClickIno::next_xindex(int elementno) const
{
int xi = xindex(elementno);
return xi + _x[xi].skip + 1;
}
inline int
ClickIno::elementno(int xindex) const
{
return _x[xindex].elementno_plus1 - 1;
}
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,503 @@
// -*- c-basic-offset: 4; related-file-name: "../../lib/integers.cc" -*-
#ifndef CLICK_INTEGERS_HH
#define CLICK_INTEGERS_HH
#include <click/glue.hh>
#include <click/type_traits.hh>
#if !HAVE___BUILTIN_FFS && HAVE_FFS && HAVE_STRINGS_H
# include <strings.h>
#endif
CLICK_DECLS
/** @file <click/integers.hh>
* @brief Functions for manipulating integers.
*/
#if HAVE_INT64_TYPES && !defined(htonq)
# if CLICK_BYTE_ORDER != CLICK_LITTLE_ENDIAN && CLICK_BYTE_ORDER != CLICK_BIG_ENDIAN
inline uint64_t htonq(uint64_t x) __attribute__((error("unknown byte order")));
# endif
/** @brief Return @a x translated from host to network byte order. */
inline uint64_t htonq(uint64_t x) {
# if CLICK_BYTE_ORDER == CLICK_LITTLE_ENDIAN
uint32_t hi = x >> 32;
uint32_t lo = x & 0xffffffff;
return (((uint64_t)htonl(lo)) << 32) | htonl(hi);
# elif CLICK_BYTE_ORDER == CLICK_BIG_ENDIAN
return x;
# else
return 0;
# endif
}
#endif
#if HAVE_INT64_TYPES && !defined(ntohq)
# if CLICK_BYTE_ORDER != CLICK_LITTLE_ENDIAN && CLICK_BYTE_ORDER != CLICK_BIG_ENDIAN
inline uint64_t htonq(uint64_t x) __attribute__((error("unknown byte order")));
# endif
/** @brief Return @a x translated from network to host byte order. */
inline uint64_t ntohq(uint64_t x) {
# if CLICK_BYTE_ORDER == CLICK_LITTLE_ENDIAN
uint32_t hi = x >> 32;
uint32_t lo = x & 0xffffffff;
return (((uint64_t)ntohl(lo)) << 32) | ntohl(hi);
# elif CLICK_BYTE_ORDER == CLICK_BIG_ENDIAN
return x;
# else
return 0;
# endif
}
#endif
/** @brief Translate @a x to network byte order.
*
* Compare htons/htonl/htonq. host_to_net_order is particularly useful in
* template functions, where the type to be translated to network byte order
* is unknown. */
inline unsigned char host_to_net_order(unsigned char x) {
return x;
}
/** @overload */
inline signed char host_to_net_order(signed char x) {
return x;
}
/** @overload */
inline char host_to_net_order(char x) {
return x;
}
/** @overload */
inline short host_to_net_order(short x) {
return htons(x);
}
/** @overload */
inline unsigned short host_to_net_order(unsigned short x) {
return htons(x);
}
/** @overload */
inline int host_to_net_order(int x) {
return htonl(x);
}
/** @overload */
inline unsigned host_to_net_order(unsigned x) {
return htonl(x);
}
#if SIZEOF_LONG == 4
/** @overload */
inline long host_to_net_order(long x) {
return htonl(x);
}
/** @overload */
inline unsigned long host_to_net_order(unsigned long x) {
return htonl(x);
}
#endif
#if HAVE_INT64_TYPES
# if SIZEOF_LONG == 8
/** @overload */
inline long host_to_net_order(long x) {
return htonq(x);
}
/** @overload */
inline unsigned long host_to_net_order(unsigned long x) {
return htonq(x);
}
# endif
# if HAVE_LONG_LONG && SIZEOF_LONG_LONG == 8
/** @overload */
inline long long host_to_net_order(long long x) {
return htonq(x);
}
/** @overload */
inline unsigned long long host_to_net_order(unsigned long long x) {
return htonq(x);
}
# endif
# if !HAVE_INT64_IS_LONG && !HAVE_INT64_IS_LONG_LONG
/** @overload */
inline int64_t host_to_net_order(int64_t x) {
return htonq(x);
}
/** @overload */
inline uint64_t host_to_net_order(uint64_t x) {
return htonq(x);
}
# endif
#endif
/** @brief Translate @a x to host byte order.
*
* Compare ntohs/ntohl/ntohq. net_to_host_order is particularly useful in
* template functions, where the type to be translated to network byte order
* is unknown. */
inline unsigned char net_to_host_order(unsigned char x) {
return x;
}
/** @overload */
inline signed char net_to_host_order(signed char x) {
return x;
}
/** @overload */
inline char net_to_host_order(char x) {
return x;
}
/** @overload */
inline short net_to_host_order(short x) {
return ntohs(x);
}
/** @overload */
inline unsigned short net_to_host_order(unsigned short x) {
return ntohs(x);
}
/** @overload */
inline int net_to_host_order(int x) {
return ntohl(x);
}
/** @overload */
inline unsigned net_to_host_order(unsigned x) {
return ntohl(x);
}
#if SIZEOF_LONG == 4
/** @overload */
inline long net_to_host_order(long x) {
return ntohl(x);
}
/** @overload */
inline unsigned long net_to_host_order(unsigned long x) {
return ntohl(x);
}
#endif
#if HAVE_INT64_TYPES
# if SIZEOF_LONG == 8
/** @overload */
inline long net_to_host_order(long x) {
return ntohq(x);
}
/** @overload */
inline unsigned long net_to_host_order(unsigned long x) {
return ntohq(x);
}
# endif
# if HAVE_LONG_LONG && SIZEOF_LONG_LONG == 8
/** @overload */
inline long long net_to_host_order(long long x) {
return ntohq(x);
}
/** @overload */
inline unsigned long long net_to_host_order(unsigned long long x) {
return ntohq(x);
}
# endif
# if !HAVE_INT64_IS_LONG && !HAVE_INT64_IS_LONG_LONG
/** @overload */
inline int64_t net_to_host_order(int64_t x) {
return ntohq(x);
}
/** @overload */
inline uint64_t net_to_host_order(uint64_t x) {
return ntohq(x);
}
# endif
#endif
// MSB is bit #1
#if HAVE___BUILTIN_CLZ && !HAVE_NO_INTEGER_BUILTINS
/** @brief Return the index of the most significant bit set in @a x.
* @return 0 if @a x = 0; otherwise the index of first bit set, where the
* most significant bit is numbered 1.
*/
inline int ffs_msb(unsigned x) {
return (x ? __builtin_clz(x) + 1 : 0);
}
#else
# define NEED_FFS_MSB_UNSIGNED 1
/** @overload */
int ffs_msb(unsigned x);
#endif
#if HAVE___BUILTIN_CLZL && !HAVE_NO_INTEGER_BUILTINS
/** @overload */
inline int ffs_msb(unsigned long x) {
return (x ? __builtin_clzl(x) + 1 : 0);
}
#elif SIZEOF_INT == SIZEOF_LONG
/** @overload */
inline int ffs_msb(unsigned long x) {
return ffs_msb(static_cast<unsigned>(x));
}
#else
# define NEED_FFS_MSB_UNSIGNED_LONG 1
/** @overload */
int ffs_msb(unsigned long x);
#endif
#if HAVE_LONG_LONG && HAVE___BUILTIN_CLZLL && !HAVE_NO_INTEGER_BUILTINS
/** @overload */
inline int ffs_msb(unsigned long long x) {
return (x ? __builtin_clzll(x) + 1 : 0);
}
#elif HAVE_LONG_LONG && SIZEOF_LONG == SIZEOF_LONG_LONG
/** @overload */
inline int ffs_msb(unsigned long long x) {
return ffs_msb(static_cast<unsigned long>(x));
}
#elif HAVE_LONG_LONG
# define NEED_FFS_MSB_UNSIGNED_LONG_LONG 1
/** @overload */
int ffs_msb(unsigned long long x);
#endif
#if HAVE_INT64_TYPES && !HAVE_INT64_IS_LONG && !HAVE_INT64_IS_LONG_LONG
# if SIZEOF_LONG >= 8
/** @overload */
inline int ffs_msb(uint64_t x) {
return ffs_msb(static_cast<unsigned long>(x));
}
# elif HAVE_LONG_LONG && SIZEOF_LONG_LONG >= 8
/** @overload */
inline int ffs_msb(uint64_t x) {
return ffs_msb(static_cast<unsigned long long>(x));
}
# else
# define NEED_FFS_MSB_UINT64_T 1
/** @overload */
int ffs_msb(uint64_t x);
# endif
#endif
// LSB is bit #1
#if HAVE___BUILTIN_FFS && !HAVE_NO_INTEGER_BUILTINS
/** @brief Return the index of the least significant bit set in @a x.
* @return 0 if @a x = 0; otherwise the index of first bit set, where the
* least significant bit is numbered 1.
*/
inline int ffs_lsb(unsigned x) {
return __builtin_ffs(x);
}
#elif HAVE_FFS && !HAVE_NO_INTEGER_BUILTINS
/** overload */
inline int ffs_lsb(unsigned x) {
return ffs(x);
}
#else
# define NEED_FFS_LSB_UNSIGNED 1
/** @overload */
int ffs_lsb(unsigned x);
#endif
#if HAVE___BUILTIN_FFSL && !HAVE_NO_INTEGER_BUILTINS
/** @overload */
inline int ffs_lsb(unsigned long x) {
return __builtin_ffsl(x);
}
#elif SIZEOF_INT == SIZEOF_LONG
/** @overload */
inline int ffs_lsb(unsigned long x) {
return ffs_lsb(static_cast<unsigned>(x));
}
#else
# define NEED_FFS_LSB_UNSIGNED_LONG 1
/** @overload */
int ffs_lsb(unsigned long x);
#endif
#if HAVE_LONG_LONG && HAVE___BUILTIN_FFSLL && !HAVE_NO_INTEGER_BUILTINS
/** @overload */
inline int ffs_lsb(unsigned long long x) {
return __builtin_ffsll(x);
}
#elif HAVE_LONG_LONG && SIZEOF_LONG == SIZEOF_LONG_LONG
/** @overload */
inline int ffs_lsb(unsigned long long x) {
return ffs_lsb(static_cast<unsigned long>(x));
}
#elif HAVE_LONG_LONG
# define NEED_FFS_LSB_UNSIGNED_LONG_LONG 1
/** @overload */
int ffs_lsb(unsigned long long x);
#endif
#if HAVE_INT64_TYPES && !HAVE_INT64_IS_LONG && !HAVE_INT64_IS_LONG_LONG
# if SIZEOF_LONG >= 8
/** @overload */
inline int ffs_lsb(uint64_t x) {
return ffs_lsb(static_cast<unsigned long>(x));
}
# elif HAVE_LONG_LONG && SIZEOF_LONG_LONG >= 8
/** @overload */
inline int ffs_lsb(uint64_t x) {
return ffs_lsb(static_cast<unsigned long long>(x));
}
# else
# define NEED_FFS_LSB_UINT64_T 1
/** @overload */
int ffs_lsb(uint64_t x);
# endif
#endif
/** @brief Return the integer approximation of @a x's square root.
* @return The integer @a y where @a y*@a y <= @a x, but
* (@a y+1)*(@a y+1) > @a x.
*/
uint32_t int_sqrt(uint32_t x);
#if HAVE_INT64_TYPES && HAVE_INT64_DIVIDE
/** @overload */
uint64_t int_sqrt(uint64_t x);
#endif
/** @brief Return @a a / @a b. */
inline uint32_t int_divide(uint32_t a, uint32_t b) {
return a / b;
}
/** @overload */
inline int32_t int_divide(int32_t a, uint32_t b) {
return a / b;
}
#if HAVE_INT64_TYPES
/** @overload */
inline uint64_t int_divide(uint64_t a, uint32_t b) {
# if CLICK_LINUXMODULE && BITS_PER_LONG < 64
do_div(a, b);
return a;
# else
return a / b;
# endif
}
/** @overload */
inline int64_t int_divide(int64_t a, uint32_t b) {
# if CLICK_LINUXMODULE && BITS_PER_LONG < 64
if (unlikely(a < 0)) {
uint64_t a_abs = -(a + 1);
do_div(a_abs, b);
return (int64_t) -a_abs - 1;
} else {
uint64_t &a_unsigned = reinterpret_cast<uint64_t &>(a);
do_div(a_unsigned, b);
return a_unsigned;
}
# else
return a / b;
# endif
}
/** @brief Multiply @a a * @a b, placing the low-order bits of the result in @a xlow
and the high-order bits in @a xhigh. */
template<typename T>
void int_multiply(T a, T b, T &xlow, T &xhigh)
{
typedef fast_half_integer<T> fasthalf;
typedef typename fasthalf::half_type half_type;
half_type al = fasthalf::low(a), ah = fasthalf::high(a),
bl = fasthalf::low(b), bh = fasthalf::high(b);
T r0 = T(al) * bl;
T r3 = T(ah) * bh;
T r1 = T(ah) * bl;
T r2 = T(al) * bh + fasthalf::high(r0) + r1;
if (r2 < r1)
r3 += fasthalf::half_value;
xhigh = r3 + fasthalf::high(r2);
xlow = (r2 << fasthalf::half_bits) + fasthalf::low(r0);
}
template<typename T>
struct has_fast_int_multiply : public false_type {
enum { check_t_integral = integer_traits<T>::is_signed };
};
#if defined(__i386__) || defined(__x86_64__)
inline void int_multiply(unsigned a, unsigned b, unsigned &xlow, unsigned &xhigh)
{
__asm__("mul %2" : "=a" (xlow), "=d" (xhigh) : "r" (a), "a" (b) : "cc");
}
template<> struct has_fast_int_multiply<unsigned> : public true_type {};
# if SIZEOF_LONG == 4 || (defined(__x86_64__) && SIZEOF_LONG == 8)
inline void int_multiply(unsigned long a, unsigned long b, unsigned long &xlow, unsigned long &xhigh)
{
__asm__("mul %2" : "=a" (xlow), "=d" (xhigh) : "r" (a), "a" (b) : "cc");
}
template<> struct has_fast_int_multiply<unsigned long> : public true_type {};
# endif
# if defined(__x86_64__) && SIZEOF_LONG_LONG == 8
inline void int_multiply(unsigned long long a, unsigned long long b, unsigned long long &xlow, unsigned long long &xhigh)
{
__asm__("mul %2" : "=a" (xlow), "=d" (xhigh) : "r" (a), "a" (b) : "cc");
}
template<> struct has_fast_int_multiply<unsigned long long> : public true_type {};
# endif
#endif
/** @brief Divide @a a / @a b, placing quotient in @a quot and returning remainder. */
inline uint32_t int_remainder(uint32_t a, uint32_t b, uint32_t &quot) {
quot = a / b;
return a - quot * b;
}
/** @overload */
inline int32_t int_remainder(int32_t a, uint32_t b, int32_t &quot) {
if (unlikely(a < 0))
quot = -(-(a + 1) / b) - 1;
else
quot = a / b;
return a - quot * b;
}
/** @overload */
inline uint32_t int_remainder(uint64_t a, uint32_t b, uint64_t &quot) {
# if CLICK_LINUXMODULE && BITS_PER_LONG < 64
uint32_t rem = do_div(a, b);
quot = a;
return rem;
# else
quot = a / b;
return a - quot * b;
# endif
}
/** @overload */
inline uint32_t int_remainder(int64_t a, uint32_t b, int64_t &quot) {
# if CLICK_LINUXMODULE && BITS_PER_LONG < 64
if (unlikely(a < 0)) {
uint64_t a_abs = -(a + 1);
uint32_t rem = do_div(a_abs, b);
quot = (int64_t) -a_abs - 1;
return rem ? b - rem : 0;
} else {
uint64_t &a_unsigned = reinterpret_cast<uint64_t &>(a);
uint32_t rem = do_div(a_unsigned, b);
quot = a_unsigned;
return rem;
}
# else
// This arithmetic is about twice as fast on my laptop as the
// alternative "div = a / b;
// rem = a - (value_type) div * b;
// if (rem < 0) div--, rem += b;",
// and 3-4x faster than "div = a / b;
// rem = a % b;
// if (rem < 0) div--, rem += b;".
if (unlikely(a < 0))
quot = -(-(a + 1) / b) - 1;
else
quot = a / b;
return a - quot * b;
# endif
}
#endif
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,408 @@
// -*- related-file-name: "../../lib/ip6address.cc" -*-
#ifndef CLICK_IP6ADDRESS_HH
#define CLICK_IP6ADDRESS_HH
#include <click/string.hh>
#include <clicknet/ip6.h>
#include <click/ipaddress.hh>
#include <click/etheraddress.hh>
#if !CLICK_TOOL
# include <click/packet.hh>
# include <click/packet_anno.hh>
#endif
CLICK_DECLS
class IP6Address { public:
typedef uninitialized_type uninitialized_t;
/** @brief Construct a zero-valued IP6Address (equal to ::). */
inline IP6Address() {
memset(&_addr, 0, sizeof(_addr));
}
/** @brief Construct an IP6Address from a sixteen-byte buffer. */
explicit inline IP6Address(const unsigned char *x) {
memcpy(&_addr, x, sizeof(_addr));
}
/** @brief Construct an IPv4-Mappped IP6Address (RFC 4291-2.5.5.2)
*
* The address has format ::FFFF:@a x. */
explicit inline IP6Address(IPAddress x) {
*this = x;
}
/** @brief Construct an IP6Address from a human-readable string. */
explicit IP6Address(const String &x); // "fec0:0:0:1::1"
/** @brief Construct an IP6Address from a C structure. */
explicit inline IP6Address(const struct in6_addr &x)
: _addr(x) {
}
/** @brief Construct an IPv4-Mapped IP6Address from a C structure. */
explicit inline IP6Address(const struct in_addr &x) {
*this = x;
}
/** @brief Construct an uninitialized IP6Address. */
inline IP6Address(const uninitialized_type &unused) {
(void) unused;
}
/** @brief Return an IP6Address equal to the prefix mask of length @a
* prefix_len.
* @param prefix_len prefix length; 0 <= @a prefix_len <= 128
*
* For example, make_prefix(0) is ::, make_prefix(12) is fff0::, and
* make_prefix(128) is ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff. Causes an
* assertion failure if @a prefix_len is out of range.
*
* @sa mask_to_prefix_len, make_inverted_prefix */
static IP6Address make_prefix(int prefix_len);
/** @brief Return an IP6Address equal to the inversion of make_prefix(@a
* prefix_len).
* @param prefix_len prefix length; 0 <= @a prefix_len <= 128
* @return ~make_prefix(@a prefix_len)
* @sa make_prefix */
static IP6Address make_inverted_prefix(int prefix_len);
typedef uint32_t (IP6Address::*unspecified_bool_type)() const;
inline operator unspecified_bool_type() const;
operator const struct in6_addr &() const { return _addr; }
operator struct in6_addr &() { return _addr; }
const struct in6_addr &in6_addr() const { return _addr; }
struct in6_addr &in6_addr() { return _addr; }
unsigned char *data() { return &_addr.s6_addr[0]; }
const unsigned char *data() const { return &_addr.s6_addr[0]; }
uint16_t *data16() { return (uint16_t *)&_addr.s6_addr[0]; }
const uint16_t *data16() const { return (uint16_t *)&_addr.s6_addr[0]; }
uint32_t *data32() { return (uint32_t *)&_addr.s6_addr[0]; }
const uint32_t *data32() const { return (uint32_t *)&_addr.s6_addr[0]; }
inline uint32_t hashcode() const;
int mask_to_prefix_len() const;
inline bool matches_prefix(const IP6Address &addr, const IP6Address &mask) const;
inline bool mask_as_specific(const IP6Address &) const;
/** @brief Test if this address contains an embedded Ethernet address.
*
* An IPv6 address with embedded Ethernet address has format
* "nnnn:nnnn:nnnn:nnnn:uuvv:wwFF:FExx:yyzz", where the embedded Ethernet
* address is "uu-vv-ww-xx-yy-zz". */
bool has_ether_address() const {
return _addr.s6_addr[11] == 0xFF && _addr.s6_addr[12] == 0xFE;
}
/** @brief Extract embedded Ethernet address into @a x.
* @param[out] x Ethernet address
* @return true iff has_ether_address() */
bool ether_address(EtherAddress &x) const;
/** @brief Return true iff the address is a IPv4-compatible address.
* NOTE: This form has been deprecated in RFC 4291 (2.5.5.1)
*
* An IPv4-mapped address has format "::w:x:y:z", where the
* IPv4 address is "w.x.y.z". */
inline bool is_ip4_compatible() const {
return data32()[0] == 0 && data32()[1] == 0
&& data32()[2] == 0;
}
/** @brief Return true iff the address is a IPv4-mapped address.
*
* An IPv4-mapped address has format "::FFFF:w:x:y:z", where the
* embedded IPv4 address is "w.x.y.z". */
inline bool is_ip4_mapped() const {
return data32()[0] == 0 && data32()[1] == 0
&& data32()[2] == htonl(0x0000FFFFU);
}
/** @brief Return true iff the address is a multicast address
* s6_addr[0] = 0xff;
*
*/
inline bool is_multicast() const {
return _addr.s6_addr[0] == 0xff;
}
/** @brief Return true iff the address is a link-local address.
* fe80::/64
*
*/
inline bool is_link_local() const {
return data32()[0] == htonl(0xfe800000) && data32()[1] == 0;
}
/** @brief Return IPv4-mapped address.
*
* @return non-empty IPv4 address iff is_ip4_mapped() is
* true. IPAddress() otherwise */
IPAddress ip4_address() const;
// bool operator==(const IP6Address &, const IP6Address &);
// bool operator!=(const IP6Address &, const IP6Address &);
// IP6Address operator&(const IP6Address &, const IP6Address &);
// IP6Address operator|(const IP6Address &, const IP6Address &);
// IP6Address operator~(const IP6Address &);
inline IP6Address &operator&=(const IP6Address &);
inline IP6Address &operator&=(const struct in6_addr &);
inline IP6Address &operator|=(const IP6Address &);
inline IP6Address &operator|=(const struct in6_addr &);
inline IP6Address &operator=(const struct in6_addr &);
inline IP6Address &operator=(const struct in_addr &);
void unparse(StringAccum &sa) const;
String unparse() const;
String unparse_expanded() const;
String s() const { return unparse(); }
inline operator String() const CLICK_DEPRECATED;
typedef const IP6Address &parameter_type;
private:
struct in6_addr _addr;
};
inline
IP6Address::operator unspecified_bool_type() const
{
const uint32_t *ai = data32();
return ai[0] || ai[1] || ai[2] || ai[3] ? &IP6Address::hashcode : 0;
}
inline
IP6Address::operator String() const
{
return unparse();
}
inline bool
operator==(const IP6Address &a, const IP6Address &b)
{
const uint32_t *ai = a.data32(), *bi = b.data32();
return ai[0] == bi[0] && ai[1] == bi[1] && ai[2] == bi[2] && ai[3] == bi[3];
}
inline bool
operator!=(const IP6Address &a, const IP6Address &b)
{
const uint32_t *ai = a.data32(), *bi = b.data32();
return ai[0] != bi[0] || ai[1] != bi[1] || ai[2] != bi[2] || ai[3] != bi[3];
}
inline StringAccum &
operator<<(StringAccum &sa, const IP6Address &a) {
a.unparse(sa);
return sa;
}
inline bool
IP6Address::matches_prefix(const IP6Address &addr, const IP6Address &mask) const
{
const uint32_t *xi = data32(), *ai = addr.data32(), *mi = mask.data32();
return ((xi[0] ^ ai[0]) & mi[0]) == 0
&& ((xi[1] ^ ai[1]) & mi[1]) == 0
&& ((xi[2] ^ ai[2]) & mi[2]) == 0
&& ((xi[3] ^ ai[3]) & mi[3]) == 0;
}
inline bool
IP6Address::mask_as_specific(const IP6Address &mask) const
{
const uint32_t *xi = data32(), *mi = mask.data32();
return ((xi[0] & mi[0]) == mi[0] && (xi[1] & mi[1]) == mi[1]
&& (xi[2] & mi[2]) == mi[2] && (xi[3] & mi[3]) == mi[3]);
}
inline IP6Address &
IP6Address::operator&=(const IP6Address &x)
{
uint32_t *ai = data32();
const uint32_t *bi = x.data32();
ai[0] &= bi[0];
ai[1] &= bi[1];
ai[2] &= bi[2];
ai[3] &= bi[3];
return *this;
}
inline IP6Address &
IP6Address::operator&=(const struct in6_addr &x)
{
uint32_t *ai = data32();
const uint32_t *bi = (uint32_t *)&x.s6_addr[0];
ai[0] &= bi[0];
ai[1] &= bi[1];
ai[2] &= bi[2];
ai[3] &= bi[3];
return *this;
}
inline IP6Address &
IP6Address::operator|=(const IP6Address &x)
{
uint32_t *ai = data32();
const uint32_t *bi = x.data32();
ai[0] |= bi[0];
ai[1] |= bi[1];
ai[2] |= bi[2];
ai[3] |= bi[3];
return *this;
}
inline IP6Address &
IP6Address::operator|=(const struct in6_addr &x)
{
uint32_t *ai = data32();
const uint32_t *bi = (uint32_t *)&x.s6_addr;
ai[0] |= bi[0];
ai[1] |= bi[1];
ai[2] |= bi[2];
ai[3] |= bi[3];
return *this;
}
inline IP6Address
operator&(const IP6Address &a, const IP6Address &b)
{
const uint32_t *ai = a.data32(), *bi = b.data32();
IP6Address result = IP6Address::uninitialized_t();
uint32_t *ri = result.data32();
ri[0] = ai[0] & bi[0];
ri[1] = ai[1] & bi[1];
ri[2] = ai[2] & bi[2];
ri[3] = ai[3] & bi[3];
return result;
}
inline IP6Address
operator&(const struct in6_addr &a, const IP6Address &b)
{
const uint32_t *ai = (const uint32_t *)&a.s6_addr[0], *bi = b.data32();
IP6Address result = IP6Address::uninitialized_t();
uint32_t *ri = result.data32();
ri[0] = ai[0] & bi[0];
ri[1] = ai[1] & bi[1];
ri[2] = ai[2] & bi[2];
ri[3] = ai[3] & bi[3];
return result;
}
inline IP6Address
operator|(const IP6Address &a, const IP6Address &b)
{
const uint32_t *ai = a.data32(), *bi = b.data32();
IP6Address result = IP6Address::uninitialized_t();
uint32_t *ri = result.data32();
ri[0] = ai[0] | bi[0];
ri[1] = ai[1] | bi[1];
ri[2] = ai[2] | bi[2];
ri[3] = ai[3] | bi[3];
return result;
}
inline IP6Address
operator~(const IP6Address &x)
{
const uint32_t *ai = x.data32();
IP6Address result = IP6Address::uninitialized_t();
uint32_t *ri = result.data32();
ri[0] = ~ai[0];
ri[1] = ~ai[1];
ri[2] = ~ai[2];
ri[3] = ~ai[3];
return result;
}
inline IP6Address &
IP6Address::operator=(const struct in6_addr &a)
{
_addr = a;
return *this;
}
inline IP6Address &
IP6Address::operator=(const struct in_addr &a)
{
memset(&_addr, 0, 10);
data16()[5] = 0xffff;
data32()[3] = a.s_addr;
return *this;
}
inline uint32_t
IP6Address::hashcode() const
{
return (data32()[2] << 1) + data32()[3];
}
#if !CLICK_TOOL
inline const IP6Address &
DST_IP6_ANNO(Packet *p)
{
return *reinterpret_cast<IP6Address *>(p->anno_u8() + DST_IP6_ANNO_OFFSET);
}
inline void
SET_DST_IP6_ANNO(Packet *p, const IP6Address &a)
{
memcpy(p->anno_u8() + DST_IP6_ANNO_OFFSET, a.data(), DST_IP6_ANNO_SIZE);
}
inline void
SET_DST_IP6_ANNO(Packet *p, const struct in6_addr &a)
{
memcpy(p->anno_u8() + DST_IP6_ANNO_OFFSET, &a, DST_IP6_ANNO_SIZE);
}
#endif
/** @class IP6AddressArg
@brief Parser class for IPv6 addresses. */
struct IP6AddressArg {
static const char *basic_parse(const String &str, IP6Address &result,
const ArgContext &args = blank_args);
static bool parse(const String &str, IP6Address &result,
const ArgContext &args = blank_args);
static bool parse(const String &str, struct in6_addr &result,
const ArgContext &args = blank_args) {
return parse(str, reinterpret_cast<IP6Address &>(result), args);
}
};
/** @class IP6PrefixArg
@brief Parser class for IPv6 address prefixes. */
class IP6PrefixArg { public:
IP6PrefixArg(bool allow_bare_address_ = false)
: allow_bare_address(allow_bare_address_) {
}
bool parse(const String &str, IP6Address &addr, int &prefix_len,
const ArgContext &args = blank_args) const;
bool parse(const String &str, IP6Address &addr, IP6Address &prefix,
const ArgContext &args = blank_args) const;
bool parse(const String &str, struct in6_addr &addr, struct in6_addr &prefix,
const ArgContext &args = blank_args) const {
return parse(str, reinterpret_cast<IP6Address &>(addr),
reinterpret_cast<IP6Address &>(prefix), args);
}
bool allow_bare_address;
};
template<> struct DefaultArg<IP6Address> : public IP6AddressArg {};
template<> struct DefaultArg<struct in6_addr> : public IP6AddressArg {};
template<> struct has_trivial_copy<IP6Address> : public true_type {};
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,250 @@
// -*- c-basic-offset: 2; related-file-name: "../../lib/ip6flowid.cc" -*-
#ifndef CLICK_IP6FLOWID_HH
#define CLICK_IP6FLOWID_HH
#include <click/ip6address.hh>
#include <click/ipflowid.hh>
#include <click/hashcode.hh>
CLICK_DECLS
class Packet;
class IP6FlowID { public:
typedef uninitialized_type uninitialized_t;
/** @brief Construct an empty flow ID.
*
* The empty flow ID has zero-valued addresses and ports. */
inline IP6FlowID();
/** @brief Construct a flow ID with the given parts.
* @param saddr source address
* @param sport source port, in network order
* @param daddr destination address
* @param dport destination port, in network order */
inline IP6FlowID(const IP6Address &, uint16_t, const IP6Address &, uint16_t);
/** @brief Construct an IPv4-Mapped flow ID with the given parts.
* @param saddr source address
* @param sport source port, in network order
* @param daddr destination address
* @param dport destination port, in network order
*
* The IPv4 addresses are converted to IPv4-mapped IPv6 addresses
* in the flow. */
inline IP6FlowID(const IPAddress &, uint16_t, const IPAddress &, uint16_t);
/** @brief Construct a flow ID from @a p's ip/ip6_header() and udp_header().
* @param p input packet
* @param reverse if true, use the reverse of @a p's flow ID
*
* @pre @a p's ip/ip6_header() must point to an IPv4 or IPv6
* header respectively, and @a p's transport header should have
* source and destination ports in the UDP-like positions; TCP,
* UDP, and DCCP fit the bill. If the packet is IPv4 the IPv4
* addresses are converted to IPv4-mapped IPv6 addresses in the flow.*/
explicit IP6FlowID(const Packet *, bool reverse = false);
/** @brief Construct a flow ID from @a ip6h and the following TCP/UDP header.
* @param iph IP header
* @param reverse if true, use the reverse of @a p's flow ID
*
* This assumes a single IPv6 header with no extension headers.The
* transport header should have source and destination ports in
* the UDP-like positions; TCP, UDP, and DCCP fit the bill. */
explicit IP6FlowID(const click_ip6 *ip6h, bool reverse = false);
/** @brief Construct an IPv4-Mapped flow ID from @a iph and the
* following TCP/UDP header.
* @param iph IP header
* @param reverse if true, use the reverse of @a p's flow ID
*
* The IPv4 header's header length, @a iph->ip_hl, is used to find
* the following transport header. This transport header should
* have source and destination ports in the UDP-like positions;
* TCP, UDP, and DCCP fit the bill. The IPv4 addresses are
* converted ip IPv4-mapped IPv6 addresses in the flow.*/
explicit IP6FlowID(const click_ip *iph, bool reverse = false);
/** @brief Construct an IPv4-Mapped flow ID from the given IPv4 @a flow.
* @param flow and IPv4 IPFlowID
*
* The parameters IPv4 addresses in the IPFlowID converted to
* IPv4-mapped IPv6 addresses. */
explicit IP6FlowID(const IPFlowID &);
/** @brief Construct an uninitialized flow ID. */
inline IP6FlowID(const uninitialized_type &unused) {
(void) unused;
}
typedef const IP6Address &(IP6FlowID::*unspecified_bool_type)() const;
inline operator unspecified_bool_type() const;
const IP6Address &saddr() const { return _saddr; }
const IP6Address &daddr() const { return _daddr; }
IPAddress saddr4() const { return _saddr.ip4_address(); }
IPAddress daddr4() const { return _daddr.ip4_address(); }
uint16_t sport() const { return _sport; }
uint16_t dport() const { return _dport; }
void set_saddr(const IP6Address &a) { _saddr = a; }
void set_daddr(const IP6Address &a) { _daddr = a; }
void set_saddr(const IPAddress a) { _saddr = a; }
void set_daddr(const IPAddress a) { _daddr = a; }
void set_sport(uint16_t p) { _sport = p; }
void set_dport(uint16_t p) { _dport = p; }
/** @brief Set this flow to the given value.
* @param saddr source address
* @param sport source port, in network order
* @param daddr destination address
* @param dport destination port, in network order */
void assign(const IP6Address &saddr, uint16_t sport, const IP6Address &daddr, uint16_t dport) {
_saddr = saddr;
_daddr = daddr;
_sport = sport;
_dport = dport;
}
/** @brief Set this flow to the given values using IPv4-mapped addresses.
* @param saddr source address
* @param sport source port, in network order
* @param daddr destination address
* @param dport destination port, in network order */
void assign(IPAddress saddr, uint16_t sport, IPAddress daddr, uint16_t dport) {
_saddr = saddr;
_daddr = daddr;
_sport = sport;
_dport = dport;
}
inline IP6FlowID reverse() const;
inline IP6FlowID rev() const CLICK_DEPRECATED;
/** @brief Indicate if this flow is IPv4.
* @return true iff the flow is IPv4 */
inline bool is_ip4_mapped() const { return _saddr.is_ip4_mapped(); }
/** @brief Return IPv4 version of a IPv4-mapped IP6FlowID.
*
* @return non-empty IPFlowID address iff this flow is using
* IPv4-mapped addresses. IPFlowID() otherwise */
IPFlowID flow_id4() const;
/** @brief Return this IP6FlowID
*
* @return this IP6FlowID */
IP6FlowID flow_id6() const;
inline IP6FlowID &operator=(const IPFlowID &);
inline hashcode_t hashcode() const;
String unparse() const;
operator String() const { return unparse(); }
String s() const { return unparse(); }
protected:
// note: several functions depend on this field order!
IP6Address _saddr;
IP6Address _daddr;
uint16_t _sport; // network byte order
uint16_t _dport; // network byte order
};
inline
IP6FlowID::IP6FlowID()
: _saddr(), _daddr(), _sport(0), _dport(0)
{
}
inline
IP6FlowID::IP6FlowID(const IP6Address &saddr, uint16_t sport,
const IP6Address &daddr, uint16_t dport)
: _saddr(saddr), _daddr(daddr), _sport(sport), _dport(dport)
{
}
inline
IP6FlowID::IP6FlowID(const IPAddress &saddr, uint16_t sport,
const IPAddress &daddr, uint16_t dport)
: _saddr(saddr), _daddr(daddr), _sport(sport), _dport(dport)
{
}
inline
IP6FlowID::IP6FlowID(const IPFlowID &flow)
{
*this = flow;
}
inline
IP6FlowID::operator unspecified_bool_type() const
{
return _saddr || _daddr ? &IP6FlowID::saddr : 0;
}
inline IP6FlowID
IP6FlowID::reverse() const
{
return IP6FlowID(_daddr, _dport, _saddr, _sport);
}
inline IP6FlowID
IP6FlowID::rev() const
{
return reverse();
}
inline IP6FlowID &
IP6FlowID::operator=(const IPFlowID &f)
{
assign(f.saddr(), f.sport(), f.daddr(), f.dport());
return *this;
}
#define ROT(v, r) ((v)<<(r) | ((unsigned)(v))>>(32-(r)))
#if 0
inline hashcode_t
IP6FlowID::hashcode() const
{
return (ROT(_saddr.hashcode(), 13)
^ ROT(_daddr.hashcode(), 23) ^ (_sport | (_dport<<16)));
}
#endif
inline hashcode_t IP6FlowID::hashcode() const
{
// more complicated hashcode, but causes less collision
uint16_t s = ntohs(sport());
uint16_t d = ntohs(dport());
hashcode_t sx = CLICK_NAME(hashcode)(saddr());
hashcode_t dx = CLICK_NAME(hashcode)(daddr());
return (ROT(sx, s%16)
^ ROT(dx, 31-d%16))
^ ((d << 16) | s);
}
#undef ROT
StringAccum &operator<<(StringAccum &sa, const IP6FlowID &flow_id);
inline bool
operator==(const IP6FlowID &a, const IP6FlowID &b)
{
return a.dport() == b.dport() && a.sport() == b.sport()
&& a.daddr() == b.daddr() && a.saddr() == b.saddr();
}
inline bool
operator!=(const IP6FlowID &a, const IP6FlowID &b)
{
return !(a == b);
}
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,39 @@
// -*- c-basic-offset: 2; related-file-name: "../../lib/ip6table.cc" -*-
#ifndef CLICK_IP6TABLE_HH
#define CLICK_IP6TABLE_HH
#include <click/glue.hh>
#include <click/vector.hh>
#include <click/ip6address.hh>
CLICK_DECLS
// IP6 routing table.
// Lookup by longest prefix.
// Each entry contains a gateway and an output index.
class IP6Table { public:
IP6Table();
~IP6Table();
bool lookup(const IP6Address &dst, IP6Address &gw, int &index) const;
void add(const IP6Address &dst, const IP6Address &mask, const IP6Address &gw, int index);
void del(const IP6Address &dst, const IP6Address &mask);
void clear() { _v.clear(); }
String dump();
private:
struct Entry {
IP6Address _dst;
IP6Address _mask;
IP6Address _gw;
int _index;
int _valid;
};
Vector<Entry> _v;
};
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,419 @@
// -*- c-basic-offset: 4; related-file-name: "../../lib/ipaddress.cc" -*-
#ifndef CLICK_IPADDRESS_HH
#define CLICK_IPADDRESS_HH
#include <click/string.hh>
#include <click/glue.hh>
#include <click/type_traits.hh>
#include <clicknet/ip.h>
CLICK_DECLS
class StringAccum;
class ArgContext;
extern const ArgContext blank_args;
class IPAddressArg;
template <typename T> class Vector;
class IPAddress { public:
typedef uninitialized_type uninitialized_t;
/** @brief Construct an IPAddress equal to 0.0.0.0. */
inline IPAddress()
: _addr(0) {
}
/** @brief Construct an IPAddress from an integer in network byte order. */
inline IPAddress(unsigned x)
: _addr(x) {
}
/** @overload */
explicit inline IPAddress(int x)
: _addr(x) {
}
/** @overload */
explicit inline IPAddress(unsigned long x)
: _addr(x) {
}
/** @overload */
explicit inline IPAddress(long x)
: _addr(x) {
}
/** @brief Construct an IPAddress from a struct in_addr. */
inline IPAddress(struct in_addr x)
: _addr(x.s_addr) {
}
/** @brief Construct an IPAddress from data.
* @param data the address data, in network byte order
*
* Bytes data[0]...data[3] are used to construct the address. */
explicit IPAddress(const unsigned char *data) {
#if HAVE_INDIFFERENT_ALIGNMENT
_addr = *(reinterpret_cast<const unsigned *>(data));
#else
memcpy(&_addr, data, 4);
#endif
}
/** @brief Constructs an IPAddress from a human-readable dotted-quad
* representation.
*
* If @a x is not a valid dotted-quad address, then the IPAddress is
* initialized to 0.0.0.0. */
explicit IPAddress(const String &x);
/** @brief Construct an uninitialized IPAddress. */
inline IPAddress(const uninitialized_type &unused) {
(void) unused;
}
/** @brief Return an IPAddress equal to the prefix mask of length @a
* prefix.
* @param prefix_len prefix length; 0 <= @a prefix_len <= 32
*
* For example, make_prefix(0) is 0.0.0.0, make_prefix(8) is 255.0.0.0, and
* make_prefix(32) is 255.255.255.255. Causes an assertion failure if @a
* prefix_len is out of range.
* @sa mask_to_prefix_len */
static IPAddress make_prefix(int prefix_len);
/** @brief Return the broadcast IP address, 255.255.255.255. */
static inline IPAddress make_broadcast() {
return IPAddress(0xFFFFFFFF);
}
/** @brief Test if the address is 0.0.0.0. */
inline bool empty() const {
return !_addr;
}
/** @brief Return the address as a uint32_t in network byte order. */
inline uint32_t addr() const {
return _addr;
}
/** @brief Return the address as a uint32_t in network byte order.
*
* Also suitable for use as an operator bool, returning true iff
* the address is not 0.0.0.0. */
inline operator uint32_t() const {
return _addr;
}
/** @brief Return true iff the address is a multicast address.
*
* These are the class D addresses, 224.0.0.0-239.255.255.255. */
inline bool is_multicast() const {
return (_addr & htonl(0xF0000000U)) == htonl(0xE0000000U);
}
inline bool is_link_local() const {
return (_addr & htonl(0xFFFF0000)) == htonl(0xA9FE0000);
}
inline struct in_addr in_addr() const;
inline operator struct in_addr() const;
inline unsigned char* data();
inline const unsigned char* data() const;
inline uint32_t hashcode() const;
int mask_to_prefix_len() const;
inline bool matches_prefix(IPAddress addr, IPAddress mask) const;
inline bool mask_as_specific(IPAddress mask) const;
inline bool mask_more_specific(IPAddress mask) const;
// bool operator==(IPAddress, IPAddress);
// bool operator==(IPAddress, uint32_t);
// bool operator!=(IPAddress, IPAddress);
// bool operator!=(IPAddress, uint32_t);
// IPAddress operator&(IPAddress, IPAddress);
// IPAddress operator|(IPAddress, IPAddress);
// IPAddress operator^(IPAddress, IPAddress);
// IPAddress operator~(IPAddress);
inline IPAddress& operator&=(IPAddress);
inline IPAddress& operator|=(IPAddress);
inline IPAddress& operator^=(IPAddress);
String unparse() const;
String unparse_mask() const;
String unparse_with_mask(IPAddress) const;
inline String s() const;
inline operator String() const CLICK_DEPRECATED;
typedef IPAddress parameter_type;
private:
uint32_t _addr;
};
/** @relates IPAddress
@brief Compare two IPAddress objects for equality. */
inline bool
operator==(IPAddress a, IPAddress b)
{
return a.addr() == b.addr();
}
/** @relates IPAddress
@brief Compare an IPAddress with a network-byte-order address value for
equality.
@param a an address
@param b an address value in network byte order */
inline bool
operator==(IPAddress a, uint32_t b)
{
return a.addr() == b;
}
/** @relates IPAddress
@brief Compare two IPAddress objects for inequality. */
inline bool
operator!=(IPAddress a, IPAddress b)
{
return a.addr() != b.addr();
}
/** @relates IPAddress
@brief Compare an IPAddress with a network-byte-order address value for
inequality.
@param a an address
@param b an address value in network byte order */
inline bool
operator!=(IPAddress a, uint32_t b)
{
return a.addr() != b;
}
/** @brief Return a pointer to the address data.
Since the address is stored in network byte order, data()[0] is the top 8
bits of the address, data()[1] the next 8 bits, and so forth. */
inline const unsigned char*
IPAddress::data() const
{
return reinterpret_cast<const unsigned char*>(&_addr);
}
/** @brief Return a pointer to the address data.
Since the address is stored in network byte order, data()[0] is the top 8
bits of the address, data()[1] the next 8 bits, and so forth. */
inline unsigned char*
IPAddress::data()
{
return reinterpret_cast<unsigned char*>(&_addr);
}
/** @brief Return a struct in_addr corresponding to the address. */
inline struct in_addr
IPAddress::in_addr() const
{
struct in_addr ia;
ia.s_addr = _addr;
return ia;
}
/** @brief Return a struct in_addr corresponding to the address. */
inline
IPAddress::operator struct in_addr() const
{
return in_addr();
}
StringAccum& operator<<(StringAccum&, IPAddress);
/** @brief Return true iff this address matches the address prefix
@a addr/@a mask.
@param addr prefix address
@param mask prefix mask
Equivalent to (@a addr & @a mask) == (*this & @a mask). The prefix address
@a addr may be nonzero outside the @a mask. */
inline bool
IPAddress::matches_prefix(IPAddress addr, IPAddress mask) const
{
return ((this->addr() ^ addr.addr()) & mask.addr()) == 0;
}
/** @brief Return true iff this address, considered as a prefix mask, is at
least as specific as @a mask.
@param mask prefix mask
Longer prefix masks are more specific than shorter ones. For example,
make_prefix(20).mask_as_specific(make_prefix(18)) is true, but
make_prefix(10).mask_as_specific(make_prefix(14)) is false.
Equivalent to (*this & @a mask) == @a mask. */
inline bool
IPAddress::mask_as_specific(IPAddress mask) const
{
return (addr() & mask.addr()) == mask.addr();
}
/** @brief Return true iff this prefix mask is more specific than @a mask.
@param mask prefix mask
Both this address and @a mask must be prefix masks -- i.e.,
mask_to_prefix_len() returns 0-32. Returns true iff this address contains
a longer prefix than @a mask. For example,
make_prefix(20).mask_more_specific(make_prefix(18)) is true, but
make_prefix(20).mask_more_specific(make_prefix(20)) is false. */
inline bool
IPAddress::mask_more_specific(IPAddress mask) const
{
return ((addr() << 1) & mask.addr()) == mask.addr();
}
/** @relates IPAddress
@brief Calculate the IPAddress representing the bitwise-and of @a a and
@a b. */
inline IPAddress
operator&(IPAddress a, IPAddress b)
{
return IPAddress(a.addr() & b.addr());
}
/** @brief Assign this address to its bitwise-and with @a a. */
inline IPAddress&
IPAddress::operator&=(IPAddress a)
{
_addr &= a._addr;
return *this;
}
/** @relates IPAddress
@brief Calculate the IPAddress representing the bitwise-or of @a a and
@a b. */
inline IPAddress
operator|(IPAddress a, IPAddress b)
{
return IPAddress(a.addr() | b.addr());
}
/** @brief Assign this address to its bitwise-or with @a a. */
inline IPAddress&
IPAddress::operator|=(IPAddress a)
{
_addr |= a._addr;
return *this;
}
/** @relates IPAddress
@brief Calculate the IPAddress representing the bitwise-xor of @a a and
@a b. */
inline IPAddress
operator^(IPAddress a, IPAddress b)
{
return IPAddress(a.addr() ^ b.addr());
}
/** @brief Assign this address to its bitwise-xor with @a a. */
inline IPAddress&
IPAddress::operator^=(IPAddress a)
{
_addr ^= a._addr;
return *this;
}
/** @relates IPAddress
@brief Calculate the IPAddress representing the bitwise complement
of @a a. */
inline IPAddress
operator~(IPAddress a)
{
return IPAddress(~a.addr());
}
/** @brief Hash function.
* @return The hash value of this IPAddress.
*
* Equal IPAddress objects always have equal hashcode() values.
*/
inline uint32_t
IPAddress::hashcode() const
{
return addr();
}
/** @brief Unparse this address into a dotted-quad format String.
@deprecated The unparse() function should be preferred to this cast.
@sa unparse */
inline
IPAddress::operator String() const
{
return unparse();
}
/** @brief Unparse this address into a dotted-quad format String.
@deprecated The unparse() function should be preferred to s().
@sa unparse */
inline String
IPAddress::s() const
{
return unparse();
}
/** @class IPAddressArg
@brief Parser class for IPv4 addresses. */
class IPAddressArg { public:
static const char *basic_parse(const char *begin, const char *end,
unsigned char value[4], int &nbytes);
static bool parse(const String &str, IPAddress &result,
const ArgContext &args = blank_args);
static bool parse(const String &str, struct in_addr &result,
const ArgContext &args = blank_args) {
return parse(str, reinterpret_cast<IPAddress &>(result), args);
}
static bool parse(const String &str, Vector<IPAddress> &result,
const ArgContext &args = blank_args);
};
/** @class IPPrefixArg
@brief Parser class for IPv4 prefixes. */
class IPPrefixArg { public:
IPPrefixArg(bool allow_bare_address_ = false)
: allow_bare_address(allow_bare_address_) {
}
bool parse(const String &str,
IPAddress &result_addr, IPAddress &result_mask,
const ArgContext &args = blank_args) const;
bool parse(const String &str,
struct in_addr &result_addr, struct in_addr &result_mask,
const ArgContext &args = blank_args) const {
return parse(str, reinterpret_cast<IPAddress &>(result_addr),
reinterpret_cast<IPAddress &>(result_mask), args);
}
bool allow_bare_address;
};
template<> struct DefaultArg<IPAddress> : public IPAddressArg {};
template<> struct DefaultArg<struct in_addr> : public IPAddressArg {};
template<> struct DefaultArg<Vector<IPAddress> > : public IPAddressArg {};
/* template<> struct has_trivial_copy<IPAddress> : public true_type {}; -- in type_traits.hh */
/** @class IPPortArg
@brief Parser class for TCP/UDP ports.
The constructor argument is the relevant IP protocol. */
class IPPortArg { public:
IPPortArg(int p)
: ip_p(p) {
assert(ip_p > 0 && ip_p < 256);
}
bool parse(const String &str, uint16_t &result,
const ArgContext &args = blank_args) const;
int ip_p;
};
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1 @@
#error "The IPAddressList class is no longer available. Use Vector<IPAddress> instead."

View File

@ -0,0 +1,192 @@
// -*- related-file-name: "../../lib/ipflowid.cc" -*-
#ifndef CLICK_IPFLOWID_HH
#define CLICK_IPFLOWID_HH
#include <click/ipaddress.hh>
#include <click/hashcode.hh>
CLICK_DECLS
class Packet;
class IPFlowID { public:
typedef uninitialized_type uninitialized_t;
/** @brief Construct an empty flow ID.
*
* The empty flow ID has zero-valued addresses and ports. */
IPFlowID()
: _saddr(), _daddr(), _sport(0), _dport(0) {
}
/** @brief Construct a flow ID with the given parts.
* @param saddr source address
* @param sport source port, in network order
* @param daddr destination address
* @param dport destination port, in network order */
IPFlowID(IPAddress saddr, uint16_t sport, IPAddress daddr, uint16_t dport)
: _saddr(saddr), _daddr(daddr), _sport(sport), _dport(dport) {
}
/** @brief Construct a flow ID from @a p's ip_header() and udp_header().
* @param p input packet
* @param reverse if true, use the reverse of @a p's flow ID
*
* @pre @a p's ip_header() must point to a first-fragment IPv4 header, and
* @a p's transport header should have source and destination ports in the
* UDP-like positions; TCP, UDP, and DCCP fit the bill. */
explicit IPFlowID(const Packet *p, bool reverse = false);
/** @brief Construct a flow ID from @a iph and the following TCP/UDP header.
* @param iph IP header
* @param reverse if true, use the reverse of @a p's flow ID
*
* The IP header's header length, @a iph->ip_hl, is used to find the
* following transport header. This transport header should have source
* and destination ports in the UDP-like positions; TCP, UDP, and DCCP fit
* the bill. */
explicit IPFlowID(const click_ip *iph, bool reverse = false);
/** @brief Construct an uninitialized flow ID. */
inline IPFlowID(const uninitialized_type &unused) {
(void) unused;
}
typedef IPAddress (IPFlowID::*unspecified_bool_type)() const;
/** @brief Return true iff the addresses of this flow ID are zero. */
operator unspecified_bool_type() const {
return _saddr || _daddr ? &IPFlowID::saddr : 0;
}
/** @brief Return this flow's source address. */
IPAddress saddr() const {
return _saddr;
}
/** @brief Return this flow's source port, in network order. */
uint16_t sport() const {
return _sport;
}
/** @brief Return this flow's destination address. */
IPAddress daddr() const {
return _daddr;
}
/** @brief Return this flow's destination port, in network order. */
uint16_t dport() const {
return _dport;
}
/** @brief Set this flow's source address to @a a. */
void set_saddr(IPAddress a) {
_saddr = a;
}
/** @brief Set this flow's source port to @a p.
* @note @a p should be in network order. */
void set_sport(uint16_t p) {
_sport = p;
}
/** @brief Set this flow's destination address to @a a. */
void set_daddr(IPAddress a) {
_daddr = a;
}
/** @brief Set this flow's destination port to @a p.
* @note @a p should be in network order. */
void set_dport(uint16_t p) {
_dport = p;
}
/** @brief Set this flow to the given value.
* @param saddr source address
* @param sport source port, in network order
* @param daddr destination address
* @param dport destination port, in network order */
void assign(IPAddress saddr, uint16_t sport, IPAddress daddr, uint16_t dport) {
_saddr = saddr;
_daddr = daddr;
_sport = sport;
_dport = dport;
}
/** @brief Return this flow's reverse, which swaps sources and destinations.
* @return IPFlowID(daddr(), dport(), saddr(), sport()) */
IPFlowID reverse() const {
return IPFlowID(_daddr, _dport, _saddr, _sport);
}
inline IPFlowID rev() const CLICK_DEPRECATED;
/** @brief Hash function.
* @return The hash value of this IPFlowID.
*
* Equal IPFlowID objects always have equal hashcode() values. */
inline hashcode_t hashcode() const;
/** @brief Unparse this address into a String.
*
* Returns a string with formatted like "(SADDR, SPORT, DADDR, DPORT)". */
String unparse() const;
inline operator String() const CLICK_DEPRECATED;
inline String s() const CLICK_DEPRECATED;
protected:
// note: several functions depend on this field order!
IPAddress _saddr;
IPAddress _daddr;
uint16_t _sport; // network byte order
uint16_t _dport; // network byte order
int unparse(char *s) const;
friend StringAccum &operator<<(StringAccum &sa, const IPFlowID &flow_id);
};
inline IPFlowID IPFlowID::rev() const
{
return reverse();
}
#define ROT(v, r) ((v)<<(r) | ((unsigned)(v))>>(32-(r)))
inline hashcode_t IPFlowID::hashcode() const
{
// more complicated hashcode, but causes less collision
uint16_t s = ntohs(sport());
uint16_t d = ntohs(dport());
hashcode_t sx = CLICK_NAME(hashcode)(saddr());
hashcode_t dx = CLICK_NAME(hashcode)(daddr());
return (ROT(sx, (s % 16) + 1) ^ ROT(dx, 31 - (d % 16)))
^ ((d << 16) | s);
}
#undef ROT
inline bool operator==(const IPFlowID &a, const IPFlowID &b)
{
return a.sport() == b.sport() && a.dport() == b.dport()
&& a.saddr() == b.saddr() && a.daddr() == b.daddr();
}
inline bool operator!=(const IPFlowID &a, const IPFlowID &b)
{
return a.sport() != b.sport() || a.dport() != b.dport()
|| a.saddr() != b.saddr() || a.daddr() != b.daddr();
}
StringAccum &operator<<(StringAccum &, const IPFlowID &);
inline IPFlowID::operator String() const
{
return unparse();
}
inline String IPFlowID::s() const
{
return unparse();
}
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,38 @@
// -*- c-basic-offset: 2; related-file-name: "../../lib/iptable.cc" -*-
#ifndef CLICK_IPTABLE_HH
#define CLICK_IPTABLE_HH
#include <click/glue.hh>
#include <click/vector.hh>
#include <click/ipaddress.hh>
CLICK_DECLS
// IP routing table.
// Lookup by longest prefix.
// Each entry contains a gateway and an output index.
class IPTable { public:
IPTable();
~IPTable();
bool lookup(IPAddress dst, IPAddress &gw, int &index) const;
void add(IPAddress dst, IPAddress mask, IPAddress gw, int index);
void del(IPAddress dst, IPAddress mask);
void clear() { _v.clear(); }
private:
struct Entry {
IPAddress dst;
IPAddress mask;
IPAddress gw;
int index;
bool valid() const { return mask || !dst; }
};
Vector<Entry> _v;
};
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,252 @@
// -*- c-basic-offset: 4; related-file-name: "../../lib/lexer.cc" -*-
#ifndef CLICK_LEXER_HH
#define CLICK_LEXER_HH
#include <click/hashtable.hh>
#include <click/router.hh>
#include <click/glue.hh>
#include <click/variableenv.hh>
CLICK_DECLS
class LexerExtra;
enum Lexemes {
lexEOF = 0,
lexIdent = 256, // see also Lexer::lexeme_string
lexVariable,
lexArrow,
lex2Arrow,
lex2Colon,
lex2Bar,
lex3Dot,
lexElementclass,
lexRequire,
lexProvide,
lexDefine
};
class Lexeme { public:
Lexeme()
: _kind(lexEOF) {
}
Lexeme(int k, const String &s, bool compact = false)
: _kind(k), _s(compact ? s.compact() : s) {
}
int kind() const { return _kind; }
bool is(int k) const { return _kind == k; }
const String &string() const { return _s; }
String &string() { return _s; }
private:
int _kind;
String _s;
};
class Lexer { public:
enum { TUNNEL_TYPE = 0, ERROR_TYPE = 1 };
class TunnelEnd;
class Compound;
typedef Router::Port Port;
typedef Router::Connection Connection;
Lexer();
virtual ~Lexer();
int begin_parse(const String &data, const String &filename, LexerExtra *, ErrorHandler * = 0);
void end_parse(int);
VariableEnvironment &global_scope() { return _global_scope; }
ErrorHandler *errh() const { return _errh; }
String remaining_text() const;
void set_remaining_text(const String &);
Lexeme lex() {
return _unlex_pos ? _unlex[--_unlex_pos] : next_lexeme();
}
void unlex(const Lexeme &t) {
assert(_unlex_pos < UNLEX_SIZE);
_unlex[_unlex_pos++] = t;
}
String lex_config() {
assert(!_unlex_pos);
return _file.lex_config(this);
}
bool expect(int, bool no_error = false);
typedef Element *(*ElementFactory)(uintptr_t);
#ifdef CLICK_LINUXMODULE
int add_element_type(const String &, ElementFactory factory, uintptr_t thunk, struct module *module, bool scoped = false);
#else
int add_element_type(const String &, ElementFactory factory, uintptr_t thunk, bool scoped = false);
#endif
int element_type(const String &name) const {
return _element_type_map[name];
}
int force_element_type(String name, bool report_error = true);
void element_type_names(Vector<String> &) const;
int remove_element_type(int t) { return remove_element_type(t, 0); }
String element_name(int) const;
String element_landmark(int) const;
void add_tunnels(String name, int *eidexes);
bool ydone() const { return !_ps; }
void ystep();
Router *create_router(Master *);
private:
enum {
max_depth = 50
};
struct FileState {
String _big_string;
const char *_end;
const char *_pos;
String _filename;
String _original_filename;
unsigned _lineno;
FileState(const String &data, const String &filename);
const char *skip_line(const char *s);
const char *skip_slash_star(const char *s);
const char *skip_backslash_angle(const char *s);
const char *skip_quote(const char *s, char end_c);
const char *process_line_directive(const char *s, Lexer *lexer);
Lexeme next_lexeme(Lexer *lexer);
String lex_config(Lexer *lexer);
String landmark() const;
};
struct ElementState;
struct ParseState;
// lexer
FileState _file;
bool _compact_config;
LexerExtra *_lextra;
Lexeme next_lexeme() {
return _file.next_lexeme(this);
}
static String lexeme_string(int);
// parser
enum { UNLEX_SIZE = 2 };
Lexeme _unlex[2];
int _unlex_pos;
// element types
struct ElementType {
ElementFactory factory;
uintptr_t thunk;
#ifdef CLICK_LINUXMODULE
struct module *module;
#endif
String name;
int next;
inline Compound* compound() const {
if (factory == compound_element_factory)
return reinterpret_cast<Compound*>(thunk);
else
return 0;
}
};
HashTable<String, int> _element_type_map;
Vector<ElementType> _element_types;
enum { ET_SCOPED = 0x80000000, ET_TMASK = 0x7FFFFFFF, ET_NULL = 0x7FFFFFFF };
int _last_element_type;
int _free_element_type;
VariableEnvironment _global_scope;
// elements
Compound *_c;
ParseState *_ps;
int _group_depth;
Vector<TunnelEnd *> _tunnels;
// compound elements
int _anonymous_offset;
// requirements
Vector<String> _requirements;
Vector<String> _libraries;
// errors
ErrorHandler *_errh;
int lerror(const char *, ...);
int lerror_syntax(const Lexeme &t);
String anon_element_name(const String &) const;
int get_element(String name, int etype,
const String &configuration = String(),
const String &filename = String(), unsigned lineno = 0);
int lexical_scoping_in() const;
void lexical_scoping_out(int);
int remove_element_type(int, int *);
int make_compound_element(int);
void expand_compound_element(int, VariableEnvironment &);
void add_router_connections(int, const Vector<int> &);
static Element* compound_element_factory(uintptr_t);
void yport(bool isoutput);
void yelement_name();
void yelement_type(int type, bool this_ident, bool this_implicit);
void yelement_config(ElementState *e, bool this_implicit);
void yelement_next();
void yconnection_connector();
void yconnection_check_useless(const Vector<int> &x, bool isoutput);
static void yconnection_analyze_ports(const Vector<int> &x, bool isoutput,
int &min_ports, int &expandable);
void yconnection_connect_all(Vector<int> &outputs, Vector<int> &inputs, int connector);
void ycompound_arguments(Compound *ct);
void ycompound();
void ycompound_next();
void ycompound_end(const Lexeme &t);
void ygroup();
void ygroup_end();
void yelementclass();
void yrequire();
void yrequire_library(const String &value);
void yvar();
void ystatement();
TunnelEnd *find_tunnel(const Port &p, bool isoutput, bool insert);
void expand_connection(const Port &p, bool isoutput, Vector<Port> &);
friend class Compound;
friend class TunnelEnd;
friend struct FileState;
};
class LexerExtra { public:
LexerExtra() { }
virtual ~LexerExtra() { }
virtual void require(String type, String value, ErrorHandler *errh);
};
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,342 @@
// libdivide.h
// Copyright 2010 - 2016 ridiculous_fish
/*
libdivide
Copyright (C) 2010 ridiculous_fish
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
libdivide@ridiculousfish.com
*/
/* modified from https://github.com/ridiculousfish/libdivide for click */
#ifndef CLICK_LIBDIVIDE_H
#define CLICK_LIBDIVIDE_H
#include <click/glue.hh>
#include <click/integers.hh>
CLICK_DECLS
#ifndef __has_builtin
#define __has_builtin(x) 0 // Compatibility with non-clang compilers.
#endif
#if defined(__SIZEOF_INT128__)
#define HAS_INT128_T 1
#endif
#if defined(__x86_64__) || defined(_WIN64) || defined(_M_X64)
#define LIBDIVIDE_IS_X86_64 1
#endif
#if defined(__i386__)
#define LIBDIVIDE_IS_i386 1
#endif
#if __GNUC__ || __clang__
#define LIBDIVIDE_GCC_STYLE_ASM 1
#endif
#define LIBDIVIDE_ASSERT(x) assert(x)
// Explanation of "more" field: bit 6 is whether to use shift path. If we are
// using the shift path, bit 7 is whether the divisor is negative in the signed
// case; in the unsigned case it is 0. Bits 0-4 is shift value (for shift
// path or mult path). In 32 bit case, bit 5 is always 0. We use bit 7 as the
// "negative divisor indicator" so that we can use sign extension to
// efficiently go to a full-width -1.
//
// u32: [0-4] shift value
// [5] ignored
// [6] add indicator
// [7] shift path
//
// s32: [0-4] shift value
// [5] shift path
// [6] add indicator
// [7] indicates negative divisor
//
// u64: [0-5] shift value
// [6] add indicator
// [7] shift path
//
// s64: [0-5] shift value
// [6] add indicator
// [7] indicates negative divisor
// magic number of 0 indicates shift path (we ran out of bits!)
//
// In s32 and s64 branchfree modes, the magic number is negated according to
// whether the divisor is negated. In branchfree strategy, it is not negated.
enum {
LIBDIVIDE_32_SHIFT_MASK = 0x1F,
LIBDIVIDE_64_SHIFT_MASK = 0x3F,
LIBDIVIDE_ADD_MARKER = 0x40,
LIBDIVIDE_U32_SHIFT_PATH = 0x80,
LIBDIVIDE_U64_SHIFT_PATH = 0x80,
LIBDIVIDE_S32_SHIFT_PATH = 0x20,
LIBDIVIDE_NEGATIVE_DIVISOR = 0x80
};
struct libdivide_u32_t {
uint32_t magic;
uint8_t more;
};
struct libdivide_u32_branchfree_t {
uint32_t magic;
uint8_t more;
};
#ifndef LIBDIVIDE_API
#define LIBDIVIDE_API static inline
#endif
LIBDIVIDE_API struct libdivide_u32_t libdivide_u32_gen(uint32_t y);
LIBDIVIDE_API struct libdivide_u32_branchfree_t libdivide_u32_branchfree_gen(uint32_t y);
LIBDIVIDE_API uint32_t libdivide_u32_do(uint32_t numer, const struct libdivide_u32_t *denom);
LIBDIVIDE_API uint32_t libdivide_u32_branchfree_do(uint32_t numer, const struct libdivide_u32_branchfree_t *denom);
LIBDIVIDE_API uint32_t libdivide_u32_recover(const struct libdivide_u32_t *denom);
LIBDIVIDE_API uint32_t libdivide_u32_branchfree_recover(const struct libdivide_u32_branchfree_t *denom);
LIBDIVIDE_API int libdivide_u32_get_algorithm(const struct libdivide_u32_t *denom);
LIBDIVIDE_API uint32_t libdivide_u32_do_alg0(uint32_t numer, const struct libdivide_u32_t *denom);
LIBDIVIDE_API uint32_t libdivide_u32_do_alg1(uint32_t numer, const struct libdivide_u32_t *denom);
LIBDIVIDE_API uint32_t libdivide_u32_do_alg2(uint32_t numer, const struct libdivide_u32_t *denom);
//////// Internal Utility Functions
static inline uint32_t libdivide__mullhi_u32(uint32_t x, uint32_t y) {
uint64_t xl = x, yl = y;
uint64_t rl = xl * yl;
return (uint32_t)(rl >> 32);
}
static inline int32_t libdivide__count_leading_zeros32(uint32_t val) {
#if __GNUC__ || __has_builtin(__builtin_clz)
// Fast way to count leading zeros
return __builtin_clz(val);
#else
int32_t result = 0;
uint32_t hi = 1U << 31;
while (~val & hi) {
hi >>= 1;
result++;
}
return result;
#endif
}
static inline int32_t libdivide__count_leading_zeros64(uint64_t val) {
#if __GNUC__ || __has_builtin(__builtin_clzll)
// Fast way to count leading zeros
return __builtin_clzll(val);
#else
uint32_t hi = val >> 32;
uint32_t lo = val & 0xFFFFFFFF;
if (hi != 0) return libdivide__count_leading_zeros32(hi);
return 32 + libdivide__count_leading_zeros32(lo);
#endif
}
// libdivide_64_div_32_to_32: divides a 64 bit uint {u1, u0} by a 32 bit
// uint {v}. The result must fit in 32 bits.
// Returns the quotient directly and the remainder in *r
#if (LIBDIVIDE_IS_i386 || LIBDIVIDE_IS_X86_64) && LIBDIVIDE_GCC_STYLE_ASM
static uint32_t libdivide_64_div_32_to_32(uint32_t u1, uint32_t u0, uint32_t v, uint32_t *r) {
uint32_t result;
__asm__("divl %[v]"
: "=a"(result), "=d"(*r)
: [v] "r"(v), "a"(u0), "d"(u1)
);
return result;
}
#else
static uint32_t libdivide_64_div_32_to_32(uint32_t u1, uint32_t u0, uint32_t v, uint32_t *r) {
uint64_t n = (((uint64_t)u1) << 32) | u0;
uint32_t result = (uint32_t)int_divide(n, v);
*r = (uint32_t)(n - result * (uint64_t)v);
return result;
}
#endif
////////// UINT32
static inline struct libdivide_u32_t libdivide_internal_u32_gen(uint32_t d, int branchfree) {
// 1 is not supported with branchfree algorithm
LIBDIVIDE_ASSERT(!branchfree || d != 1);
struct libdivide_u32_t result;
const uint32_t floor_log_2_d = 31 - libdivide__count_leading_zeros32(d);
if ((d & (d - 1)) == 0) {
// Power of 2
if (! branchfree) {
result.magic = 0;
result.more = floor_log_2_d | LIBDIVIDE_U32_SHIFT_PATH;
} else {
// We want a magic number of 2**32 and a shift of floor_log_2_d
// but one of the shifts is taken up by LIBDIVIDE_ADD_MARKER, so we
// subtract 1 from the shift
result.magic = 0;
result.more = (floor_log_2_d-1) | LIBDIVIDE_ADD_MARKER;
}
} else {
uint8_t more;
uint32_t rem, proposed_m;
proposed_m = libdivide_64_div_32_to_32(1U << floor_log_2_d, 0, d, &rem);
LIBDIVIDE_ASSERT(rem > 0 && rem < d);
const uint32_t e = d - rem;
// This power works if e < 2**floor_log_2_d.
if (!branchfree && (e < (1U << floor_log_2_d))) {
// This power works
more = floor_log_2_d;
} else {
// We have to use the general 33-bit algorithm. We need to compute
// (2**power) / d. However, we already have (2**(power-1))/d and
// its remainder. By doubling both, and then correcting the
// remainder, we can compute the larger division.
// don't care about overflow here - in fact, we expect it
proposed_m += proposed_m;
const uint32_t twice_rem = rem + rem;
if (twice_rem >= d || twice_rem < rem) proposed_m += 1;
more = floor_log_2_d | LIBDIVIDE_ADD_MARKER;
}
result.magic = 1 + proposed_m;
result.more = more;
// result.more's shift should in general be ceil_log_2_d. But if we
// used the smaller power, we subtract one from the shift because we're
// using the smaller power. If we're using the larger power, we
// subtract one from the shift because it's taken care of by the add
// indicator. So floor_log_2_d happens to be correct in both cases.
}
return result;
}
struct libdivide_u32_t libdivide_u32_gen(uint32_t d) {
return libdivide_internal_u32_gen(d, 0);
}
struct libdivide_u32_branchfree_t libdivide_u32_branchfree_gen(uint32_t d) {
struct libdivide_u32_t tmp = libdivide_internal_u32_gen(d, 1);
struct libdivide_u32_branchfree_t ret = {tmp.magic, (uint8_t)(tmp.more & LIBDIVIDE_32_SHIFT_MASK)};
return ret;
}
uint32_t libdivide_u32_do(uint32_t numer, const struct libdivide_u32_t *denom) {
uint8_t more = denom->more;
if (more & LIBDIVIDE_U32_SHIFT_PATH) {
return numer >> (more & LIBDIVIDE_32_SHIFT_MASK);
}
else {
uint32_t q = libdivide__mullhi_u32(denom->magic, numer);
if (more & LIBDIVIDE_ADD_MARKER) {
uint32_t t = ((numer - q) >> 1) + q;
return t >> (more & LIBDIVIDE_32_SHIFT_MASK);
}
else {
return q >> more; // all upper bits are 0 - don't need to mask them off
}
}
}
uint32_t libdivide_u32_recover(const struct libdivide_u32_t *denom) {
uint8_t more = denom->more;
uint8_t shift = more & LIBDIVIDE_32_SHIFT_MASK;
if (more & LIBDIVIDE_U32_SHIFT_PATH) {
return 1U << shift;
} else if (! (more & LIBDIVIDE_ADD_MARKER)) {
// We compute q = n/d = n*m / 2^(32 + shift)
// Therefore we have d = 2^(32 + shift) / m
// We need to ceil it.
// We know d is not a power of 2, so m is not a power of 2,
// so we can just add 1 to the floor
uint32_t hi_dividend = 1U << shift;
uint32_t rem_ignored;
return 1 + libdivide_64_div_32_to_32(hi_dividend, 0, denom->magic, &rem_ignored);
} else {
// Here we wish to compute d = 2^(32+shift+1)/(m+2^32).
// Notice (m + 2^32) is a 33 bit number. Use 64 bit division for now
// Also note that shift may be as high as 31, so shift + 1 will
// overflow. So we have to compute it as 2^(32+shift)/(m+2^32), and
// then double the quotient and remainder.
// TODO: do something better than 64 bit math
uint64_t half_n = 1ULL << (32 + shift);
uint64_t d = (1ULL << 32) | denom->magic;
// Note that the quotient is guaranteed <= 32 bits, but the remainder
// may need 33!
uint32_t half_q = (uint32_t)int_divide(half_n, d);
uint64_t rem = half_n - half_q * d; // broken
// We computed 2^(32+shift)/(m+2^32)
// Need to double it, and then add 1 to the quotient if doubling th
// remainder would increase the quotient.
// Note that rem<<1 cannot overflow, since rem < d and d is 33 bits
uint32_t full_q = half_q + half_q + ((rem<<1) >= d);
// We rounded down in gen unless we're a power of 2 (i.e. in branchfree case)
// We can detect that by looking at m. If m zero, we're a power of 2
return full_q + (denom->magic != 0);
}
}
uint32_t libdivide_u32_branchfree_recover(const struct libdivide_u32_branchfree_t *denom) {
struct libdivide_u32_t denom_u32 = {denom->magic, (uint8_t)(denom->more | LIBDIVIDE_ADD_MARKER)};
return libdivide_u32_recover(&denom_u32);
}
int libdivide_u32_get_algorithm(const struct libdivide_u32_t *denom) {
uint8_t more = denom->more;
if (more & LIBDIVIDE_U32_SHIFT_PATH) return 0;
else if (! (more & LIBDIVIDE_ADD_MARKER)) return 1;
else return 2;
}
uint32_t libdivide_u32_do_alg0(uint32_t numer, const struct libdivide_u32_t *denom) {
return numer >> (denom->more & LIBDIVIDE_32_SHIFT_MASK);
}
uint32_t libdivide_u32_do_alg1(uint32_t numer, const struct libdivide_u32_t *denom) {
uint32_t q = libdivide__mullhi_u32(denom->magic, numer);
return q >> denom->more;
}
uint32_t libdivide_u32_do_alg2(uint32_t numer, const struct libdivide_u32_t *denom) {
// denom->add != 0
uint32_t q = libdivide__mullhi_u32(denom->magic, numer);
uint32_t t = ((numer - q) >> 1) + q;
// Note that this mask is typically free. Only the low bits are meaningful
// to a shift, so compilers can optimize out this AND.
return t >> (denom->more & LIBDIVIDE_32_SHIFT_MASK);
}
uint32_t libdivide_u32_branchfree_do(uint32_t numer, const struct libdivide_u32_branchfree_t *denom) {
// same as alg 2
uint32_t q = libdivide__mullhi_u32(denom->magic, numer);
uint32_t t = ((numer - q) >> 1) + q;
return t >> denom->more;
}
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,564 @@
#ifndef CLICK_LIST_HH
#define CLICK_LIST_HH 1
/*
* list.hh -- List template
* Eddie Kohler
*
* Copyright (c) 2008 Meraki, Inc.
*
* 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.
*/
CLICK_DECLS
#define LIST_HEAD_MARKER 0 /* ((T *) 1) */
/** @file <click/list.hh>
* @brief Click's doubly-linked list container template.
*/
template <typename T> class List_member;
template <typename T, List_member<T> T::*member> class List;
/** @class List
@brief Doubly-linked list template.
The List template, and its helper template List_member, implement a generic
doubly-linked list. The list is <em>intrusive</em> in that the container
does not manage space for its contents. The user provides space for
contained elements, and must delete elements when they are no longer needed.
(This is unlike Vector or HashTable, which manage space for their contents.)
The main advantage of intrusive containers is that a single element can be
on multiple lists.
Here's an example linked list of integers built using List and List_member.
@code
#include <click/list.hh>
struct intlist_node {
int value;
List_member<intlist_node> link;
intlist_node(int v)
: value(v) {
}
};
typedef List<intlist_node, &intlist_node::link> intlist;
void make_intlist(intlist &l, int begin, int end, int step) {
for (int i = begin; i < end; i += step)
l.push_back(new intlist_node(i));
// Note that l does not manage its contents' memory!
// Whoever destroys l should first delete its contents,
// for example by calling trash_intlist(l).
}
void print_intlist(const intlist &l) {
size_t n = 0;
for (intlist::const_iterator it = l.begin(); it != l.end(); ++it, ++n)
click_chatter("#%ld: %d\n", (long) n, it->value);
}
void trash_intlist(intlist &l) {
while (!l.empty()) {
intlist_node *n = l.front();
l.pop_front();
delete n;
}
}
template <typename T>
void remove_every_other(T &list) {
typename T::iterator it = list.begin();
while (it != l.end()) {
++it;
if (it != l.end())
it = list.erase(it);
}
}
@endcode
*/
/** @class List_member
@brief Member of classes to be placed on a List.
Any class type that will be placed on a List must have a publicly accessible
List_member member. This member is supplied as the second template argument
to List. List_member allows users to fetch the next-element and
previous-element pointers, but all modifications must take place via List
functions like List::push_back() and List::insert(). List_member has
private copy constructor and default assignment operators.
@sa List
*/
template <typename T>
class List_member { public:
/** @brief Construct an isolated List_member. */
List_member()
: _next(), _prev() {
}
/** @brief Return the next element in the list. */
T *next() {
return _next;
}
/** @overload */
const T *next() const {
return _next;
}
/** @brief Return the previous element in the list. */
T *prev() {
return _prev != LIST_HEAD_MARKER ? _prev : 0;
}
/** @overload */
const T *prev() const {
return _prev != LIST_HEAD_MARKER ? _prev : 0;
}
private:
T *_next;
T *_prev;
List_member(const List_member<T> &x);
List_member<T> &operator=(const List_member<T> &x);
template <typename X, List_member<X> X::*member> friend class List;
};
template <typename T, List_member<T> T::*member>
class List { public:
typedef T *pointer;
typedef const T *const_pointer;
class const_iterator;
class iterator;
typedef size_t size_type;
/** @brief Construct an empty list. */
List()
: _head(0), _tail(0) {
}
/** @brief Return an iterator for the first element in the list. */
iterator begin() {
return iterator(_head, this);
}
/** @overload */
const_iterator begin() const {
return const_iterator(_head, this);
}
/** @brief Return an iterator for the end of the list.
* @invariant end().live() == false */
iterator end() {
return iterator(this);
}
/** @overload */
const_iterator end() const {
return const_iterator(this);
}
/** @brief Return true iff size() == 0.
* @note Always O(1) time, whereas size() takes O(N) time. */
bool empty() const {
return _head == 0;
}
/** @brief Return the number of elements in the list.
* @note Takes O(N) time, where N is the number of elements. */
size_type size() const {
size_type n = 0;
for (T *x = _head; x; x = (x->*member)._next)
++n;
return n;
}
/** @brief Return the first element in the list.
*
* Returns a null pointer if the list is empty. */
pointer front() {
return _head;
}
/** @overload */
const_pointer front() const {
return _head;
}
/** @brief Return the last element in the list.
*
* Returns a null pointer if the list is empty. */
pointer back() {
return _tail;
}
/** @overload */
const_pointer back() const {
return _tail;
}
/** @brief Insert a new element at the beginning of the list.
* @param x new element
* @pre isolated(@a x) */
void push_front(pointer x) {
assert(x && isolated(x));
if (((x->*member)._next = _head))
(_head->*member)._prev = x;
else
_tail = x;
_head = x;
(_head->*member)._prev = LIST_HEAD_MARKER;
}
/** @brief Insert a new element at the end of the list.
* @param x new element
* @pre isolated(@a x) */
void push_back(pointer x) {
assert(x && !(x->*member)._next && !(x->*member)._prev);
if (((x->*member)._prev = _tail))
(_tail->*member)._next = x;
else {
_head = x;
(_head->*member)._prev = LIST_HEAD_MARKER;
}
_tail = x;
}
/** @brief Remove the element at the beginning of the list.
* @pre !empty() */
void pop_front() {
assert(_head);
pointer x = _head;
if ((_head = (x->*member)._next) != LIST_HEAD_MARKER)
(_head->*member)._prev = LIST_HEAD_MARKER;
else
_head = _tail = 0;
(x->*member)._next = (x->*member)._prev = 0;
}
/** @brief Remove the element at the end of the list.
* @pre !empty() */
void pop_back() {
assert(_head);
pointer x = _tail;
if ((_tail = (x->*member)._prev) != LIST_HEAD_MARKER)
(_tail->*member)._next = 0;
else
_head = _tail = 0;
(x->*member)._next = (x->*member)._prev = 0;
}
/** @brief Insert an element before @a pos.
* @param pos position to insert (if null, insert at end of list)
* @param x new element
* @pre (!@a pos || contains(@a pos)) && isolated(@a x) */
void insert(pointer pos, pointer x) {
assert(x && isolated(x));
T **pprev = (pos ? &(pos->*member)._prev : &_tail);
if (((x->*member)._prev = *pprev) != LIST_HEAD_MARKER)
((x->*member)._prev->*member)._next = x;
else
_head = x;
*pprev = x;
(x->*member)._next = pos;
}
/** @brief Insert an element before @a it.
* @param it position to insert
* @param x new element
* @return an iterator pointing to @a x
* @pre isolated(@a x) */
iterator insert(iterator it, pointer x) {
insert(it.get(), x);
return iterator(x);
}
/** @brief Insert the elements in [@a first, @a last) before @a it.
* @param it position to insert
* @param first iterator to beginning of insertion sequence
* @param last iterator to end of insertion sequence
* @pre isolated(@a x) for each @a x in [@a first, @a last) */
template <typename InputIterator>
void insert(iterator it, InputIterator first, InputIterator last) {
while (first != last) {
insert(it, *first);
++first;
}
}
/** @brief Remove @a x from the list.
* @param x element to remove
* @pre contains(@a x) */
void erase(pointer x) {
assert(x);
T *n = (x->*member)._next, *p = (x->*member)._prev;
if (n)
(n->*member)._prev = p;
else
_tail = (p != LIST_HEAD_MARKER ? p : 0);
if (p != LIST_HEAD_MARKER)
(p->*member)._next = n;
else
_head = n;
(x->*member)._next = (x->*member)._prev = 0;
}
/** @brief Remove the element pointed to by @a it from the list.
* @param it element to remove
* @return iterator pointing to the element after the removed element
* @pre @a it.live() */
iterator erase(iterator it) {
assert(it);
iterator next = iterator((it.get()->*member)._next);
erase(it.get());
return next;
}
/** @brief Remove the elements in [@a first, @a last) from the list.
* @param first iterator to beginning of removal subsequence
* @param last iterator to end of removal subsequence
* @return iterator pointing to the element after the removed subsequence */
iterator erase(iterator first, iterator last) {
while (first != last)
first = erase(first);
return first;
}
/** @brief Remove all elements from the list.
* @note Equivalent to erase(begin(), end()). */
void clear() {
while (T *x = _head) {
_head = (x->*member)._next;
(x->*member)._next = (x->*member)._prev = 0;
}
_tail = 0;
}
/** @brief Remove all elements from the list.
*
* Unlike clear(), this function does not erase() any of the elements of
* this list: those elements' next() and prev() members remain
* unchanged. */
void __clear() {
_head = _tail = 0;
}
/** @brief Exchange list contents with list @a x. */
void swap(List<T, member> &x) {
T *h = x._head, *t = x._tail;
x._head = _head, x._tail = _tail;
_head = h, _tail = t;
}
/** @brief Check if @a x is isolated.
*
* An isolated element is not a member of any list. */
bool isolated(const_pointer x) {
return !(x->*member)._next && !(x->*member)._prev && x != _head;
}
/** @brief Check if @a x is a member of this list. */
bool contains(const_pointer x) const {
if (!isolated(x))
for (const_pointer *it = _head; it; it = (it->*member).next())
if (x == it)
return true;
return false;
}
/** @class List::const_iterator
* @brief Const iterator type for List. */
class const_iterator { public:
/** @brief Construct an invalid iterator. */
const_iterator()
: _x(), _list() {
}
/** @brief Construct an iterator pointing at @a x. */
const_iterator(const T *x)
: _x(const_cast<T *>(x)), _list() {
}
/** @brief Construct an end iterator for @a list. */
const_iterator(const List<T, member> *list)
: _x(), _list(list) {
}
/** @brief Construct an iterator pointing at @a x in @a list. */
const_iterator(const T *x, const List<T, member> *list)
: _x(const_cast<T *>(x)), _list(list) {
}
typedef bool (const_iterator::*unspecified_bool_type)() const;
/** @brief Test if this iterator points to a valid list element. */
operator unspecified_bool_type() const {
return _x != 0 ? &const_iterator::live : 0;
}
/** @brief Test if this iterator points to a valid list element. */
bool live() const {
return _x != 0;
}
/** @brief Return the current list element or null. */
const T *get() const {
return _x;
}
/** @brief Return the current list element or null. */
const T *operator->() const {
return _x;
}
/** @brief Return the current list element. */
const T &operator*() const {
return *_x;
}
/** @brief Advance this iterator to the next element. */
void operator++() {
assert(_x);
_x = (_x->*member).next();
}
/** @brief Advance this iterator to the next element. */
void operator++(int) {
++*this;
}
/** @brief Advance this iterator to the previous element. */
void operator--() {
assert(_x ? (bool) (_x->*member).prev() : _list && _list->back());
if (_x)
_x = (_x->*member).prev();
else
_x = const_cast<T *>(_list->back());
}
/** @brief Advance this iterator to the previous element. */
void operator--(int) {
--*this;
}
/** @brief Move this iterator forward by @a x positions.
* @return reference to this iterator
* @note This function takes O(abs(@a x)) time. */
const_iterator &operator+=(int x) {
for (; x > 0; --x)
++*this;
for (; x < 0; ++x)
--*this;
return *this;
}
/** @brief Move this iterator backward by @a x positions.
* @return reference to this iterator
* @note This function takes O(abs(@a x)) time. */
const_iterator &operator-=(int x) {
for (; x > 0; --x)
--*this;
for (; x < 0; ++x)
++*this;
return *this;
}
/** @brief Return an iterator @a x positions ahead. */
const_iterator operator+(int x) const {
const_iterator it(*this);
return it += x;
}
/** @brief Return an iterator @a x positions behind. */
const_iterator operator-(int x) const {
const_iterator it(*this);
return it -= x;
}
/** @brief Test if this iterator equals @a x. */
bool operator==(const_iterator x) const {
return _x == x._x;
}
/** @brief Test if this iterator does not equal @a x. */
bool operator!=(const_iterator x) const {
return _x != x._x;
}
private:
T *_x;
const List<T, member> *_list;
friend class iterator;
};
/** @class List::iterator
* @brief Iterator type for List. */
class iterator : public const_iterator { public:
/** @brief Construct an invalid iterator. */
iterator()
: const_iterator() {
}
/** @brief Construct an iterator pointing at @a x. */
iterator(T *x)
: const_iterator(x) {
}
/** @brief Construct an end iterator for @a list. */
iterator(List<T, member> *list)
: const_iterator(list) {
}
/** @brief Construct an iterator pointing at @a x in @a list. */
iterator(T *x, List<T, member> *list)
: const_iterator(x, list) {
}
/** @brief Return the current list element or null. */
T *get() const {
return this->_x;
}
/** @brief Return the current list element or null. */
T *operator->() const {
return this->_x;
}
/** @brief Return the current list element. */
T &operator*() const {
return *this->_x;
}
/** @brief Move this iterator forward by @a x positions.
* @return reference to this iterator
* @note This function takes O(abs(@a x)) time. */
iterator &operator+=(int x) {
for (; x > 0; --x)
++*this;
for (; x < 0; ++x)
--*this;
return *this;
}
/** @brief Move this iterator backward by @a x positions.
* @return reference to this iterator
* @note This function takes O(abs(@a x)) time. */
iterator &operator-=(int x) {
for (; x > 0; --x)
--*this;
for (; x < 0; ++x)
++*this;
return *this;
}
/** @brief Return an iterator @a x positions ahead. */
iterator operator+(int x) const {
iterator it(*this);
return it += x;
}
/** @brief Return an iterator @a x positions behind. */
iterator operator-(int x) const {
iterator it(*this);
return it -= x;
}
};
private:
T *_head;
T *_tail;
List(const List<T, member> &x);
List<T, member> &operator=(const List<T, member> &x);
};
#undef LIST_HEAD_MARKER
CLICK_ENDDECLS
#endif /* CLICK_LIST_HH */

View File

@ -0,0 +1,195 @@
#ifndef CLICK_LLRPC_H
#define CLICK_LLRPC_H
#if CLICK_LINUXMODULE
# include <click/cxxprotect.h>
CLICK_CXX_PROTECT
# include <linux/errno.h>
# include <linux/ioctl.h>
# include <asm/uaccess.h>
CLICK_CXX_UNPROTECT
# include <click/cxxunprotect.h>
#elif CLICK_BSDMODULE
# include <sys/errno.h>
# include <sys/ioccom.h>
#else
# include <errno.h>
# include <sys/ioctl.h>
#endif
/* Click low-level RPC interface */
/* Ioctl numbers are not consistent across platforms unless you #define
HAVE_PORTABLE_LLRPC. */
#define _CLICK_NET_IOC_VOID 0x20000000
#define _CLICK_NET_IOC_OUT 0x40000000
#define _CLICK_NET_IOC_IN 0x80000000
#if HAVE_PORTABLE_LLRPC || !defined(__linux__)
# define _CLICK_IOC_VOID _CLICK_NET_IOC_VOID
# define _CLICK_IOC_OUT _CLICK_NET_IOC_OUT
# define _CLICK_IOC_IN _CLICK_NET_IOC_IN
#else
# define _CLICK_IOC_VOID (_IOC_NONE << _IOC_DIRSHIFT)
# define _CLICK_IOC_OUT (_IOC_READ << _IOC_DIRSHIFT)
# define _CLICK_IOC_IN (_IOC_WRITE << _IOC_DIRSHIFT)
#endif
#define _CLICK_IOC_BASE_MASK 0x0FFFFFFF
#define _CLICK_IOC_SAFE 0x00008000
#define _CLICK_IOC_FLAT 0x00004000
#define _CLICK_IOC_SIZE(io) ((io) >> 16 & 0xFFF)
/* _CLICK_IO[S]: data transfer direction unknown, pass pointer unchanged;
_CLICK_IOR[S]: data of specified size sent from kernel to user;
_CLICK_IOW[S]: data of specified size sent from user to kernel;
_CLICK_IOWR[S]: data of specified size transferred in both directions. */
/* "Non-safe" LLRPCs will not be performed in parallel with other LLRPCs or
handlers. They will also block the router threads. */
#define _CLICK_IOX(d, n, sz) ((d) | ((sz) << 16) | (n))
#define _CLICK_IO(n) _CLICK_IOX(_CLICK_IOC_VOID, (n), 0)
#define _CLICK_IOR(n, sz) _CLICK_IOX(_CLICK_IOC_OUT, (n), (sz))
#define _CLICK_IOW(n, sz) _CLICK_IOX(_CLICK_IOC_IN, (n), (sz))
#define _CLICK_IOWR(n, sz) _CLICK_IOX(_CLICK_IOC_IN|_CLICK_IOC_OUT, (n), (sz))
/* "Safe" LLRPCs may be performed in parallel with read handlers and other
safe LLRPCs, but not with write handlers or unsafe LLRPCs. They will not
block the router threads. */
#define _CLICK_IOS(n) _CLICK_IOX(_CLICK_IOC_VOID|_CLICK_IOC_SAFE, (n), 0)
#define _CLICK_IORS(n, sz) _CLICK_IOX(_CLICK_IOC_OUT|_CLICK_IOC_SAFE, (n), (sz))
#define _CLICK_IOWS(n, sz) _CLICK_IOX(_CLICK_IOC_IN|_CLICK_IOC_SAFE, (n), (sz))
#define _CLICK_IOWRS(n, sz) _CLICK_IOX(_CLICK_IOC_IN|_CLICK_IOC_OUT|_CLICK_IOC_SAFE, (n), (sz))
/* "Flat" LLRPCs do not contain pointers -- all data read or written is
contained in the size. They can be safe or unsafe. */
#define _CLICK_IORF(n, sz) _CLICK_IOX(_CLICK_IOC_OUT|_CLICK_IOC_FLAT, (n), (sz))
#define _CLICK_IOWF(n, sz) _CLICK_IOX(_CLICK_IOC_IN|_CLICK_IOC_FLAT, (n), (sz))
#define _CLICK_IOWRF(n, sz) _CLICK_IOX(_CLICK_IOC_IN|_CLICK_IOC_OUT|_CLICK_IOC_FLAT, (n), (sz))
#define _CLICK_IORSF(n, sz) _CLICK_IOX(_CLICK_IOC_OUT|_CLICK_IOC_SAFE|_CLICK_IOC_FLAT, (n), (sz))
#define _CLICK_IOWSF(n, sz) _CLICK_IOX(_CLICK_IOC_IN|_CLICK_IOC_SAFE|_CLICK_IOC_FLAT, (n), (sz))
#define _CLICK_IOWRSF(n, sz) _CLICK_IOX(_CLICK_IOC_IN|_CLICK_IOC_OUT|_CLICK_IOC_SAFE|_CLICK_IOC_FLAT, (n), (sz))
#define CLICK_LLRPC_PROXY _CLICK_IO(0)
#define CLICK_LLRPC_GET_RATE _CLICK_IOWRSF(1, 4)
#define CLICK_LLRPC_GET_RATES _CLICK_IOS(2)
#define CLICK_LLRPC_GET_COUNT _CLICK_IOWRSF(3, 4)
#define CLICK_LLRPC_GET_COUNTS _CLICK_IOS(4)
#define CLICK_LLRPC_GET_SWITCH _CLICK_IORSF(5, 4)
#define CLICK_LLRPC_SET_SWITCH _CLICK_IOWF(6, 4)
#define CLICK_LLRPC_MAP_IPADDRESS _CLICK_IOWRF(7, 4)
#define CLICK_LLRPC_IPREWRITER_MAP_TCP _CLICK_IOWRF(8, 12)
#define CLICK_LLRPC_IPREWRITER_MAP_UDP _CLICK_IOWRF(9, 12)
#define CLICK_LLRPC_IPRATEMON_LEVEL_FWD_AVG _CLICK_IO(10)
#define CLICK_LLRPC_IPRATEMON_LEVEL_REV_AVG _CLICK_IO(11)
#define CLICK_LLRPC_IPRATEMON_FWD_N_REV_AVG _CLICK_IO(12)
#define CLICK_LLRPC_IPRATEMON_SET_ANNO_LEVEL _CLICK_IO(13)
#define CLICK_IOC_TOUSERDEVICE_GET_MULTI _CLICK_IOS(15)
#define CLICK_IOC_TOUSERDEVICE_SET_MULTI _CLICK_IOS(16)
#define CLICK_LLRPC_RAW_HANDLER _CLICK_IOS(17)
#define CLICK_LLRPC_ABANDON_HANDLER _CLICK_IOS(18)
#define CLICK_LLRPC_CALL_HANDLER _CLICK_IO(19)
struct click_llrpc_proxy_st {
void* proxied_handler; /* const Router::Handler* */
uint32_t proxied_command;
void* proxied_data;
};
#define CLICK_LLRPC_COUNTS_SIZE 8
struct click_llrpc_counts_st {
uint32_t n;
uint32_t keys[CLICK_LLRPC_COUNTS_SIZE];
uint32_t values[CLICK_LLRPC_COUNTS_SIZE];
};
#define CLICK_LLRPC_CALL_HANDLER_FLAG_RAW 1
struct click_llrpc_call_handler_st {
int flags;
size_t errorlen;
void *errorbuf;
};
/* data manipulation */
#if CLICK_USERLEVEL || CLICK_MINIOS
# define CLICK_LLRPC_GET_DATA(local, remote, size) (memcpy(local, remote, size), 0)
# define CLICK_LLRPC_PUT_DATA(remote, local, size) (memcpy(remote, local, size), 0)
# define CLICK_LLRPC_GET(local_obj, remote_addr) (memcpy(&(local_obj), remote_addr, sizeof(local_obj)), 0)
# define CLICK_LLRPC_PUT(remote_addr, local_obj) (memcpy(remote_addr, &(local_obj), sizeof(local_obj)), 0)
#elif CLICK_LINUXMODULE
# ifdef __cplusplus
# define __CLICK_LLRPC_CAST(x) reinterpret_cast< x >
# else
# define __CLICK_LLRPC_CAST(x) (x)
# endif
# define __CLICK_LLRPC_GENERIC_GET_DATA(local, remote, size) \
(copy_from_user(local, remote, size) > 0 ? -EFAULT : 0)
# define __CLICK_LLRPC_CONSTANT_GET_DATA(local, remote, size) \
(size == 1 ? get_user(*__CLICK_LLRPC_CAST(unsigned char *)(local), __CLICK_LLRPC_CAST(unsigned char *)(remote)) \
: (size == 2 ? get_user(*__CLICK_LLRPC_CAST(unsigned short *)(local), __CLICK_LLRPC_CAST(unsigned short *)(remote)) \
: (size == 4 ? get_user(*__CLICK_LLRPC_CAST(unsigned *)(local), __CLICK_LLRPC_CAST(unsigned *)(remote)) \
: __CLICK_LLRPC_GENERIC_GET_DATA(local, remote, size))))
# define __CLICK_LLRPC_GENERIC_PUT_DATA(remote, local, size) \
(copy_to_user(remote, local, size) > 0 ? -EFAULT : 0)
# define __CLICK_LLRPC_CONSTANT_PUT_DATA(remote, local, size) \
(size == 1 ? put_user(*__CLICK_LLRPC_CAST(const unsigned char *)(local), __CLICK_LLRPC_CAST(unsigned char *)(remote)) \
: (size == 2 ? put_user(*__CLICK_LLRPC_CAST(const unsigned short *)(local), __CLICK_LLRPC_CAST(unsigned short *)(remote)) \
: (size == 4 ? put_user(*__CLICK_LLRPC_CAST(const unsigned *)(local), __CLICK_LLRPC_CAST(unsigned *)(remote)) \
: __CLICK_LLRPC_GENERIC_PUT_DATA(remote, local, size))))
# define CLICK_LLRPC_GET_DATA(local, remote, size) \
(__builtin_constant_p(size) && size <= 4 \
? __CLICK_LLRPC_CONSTANT_GET_DATA(local, remote, size) \
: __CLICK_LLRPC_GENERIC_GET_DATA(local, remote, size))
# define CLICK_LLRPC_PUT_DATA(remote, local, size) \
(__builtin_constant_p(size) && size <= 4 \
? __CLICK_LLRPC_CONSTANT_PUT_DATA(remote, local, size) \
: __CLICK_LLRPC_GENERIC_PUT_DATA(remote, local, size))
# define CLICK_LLRPC_GET(local_obj, remote_addr) \
get_user((local_obj), (remote_addr))
# define CLICK_LLRPC_PUT(remote_addr, local_obj) \
put_user((local_obj), (remote_addr))
#elif CLICK_BSDMODULE
/*
* XXX LLRPC isn't implemented for BSD yet.
*/
# define CLICK_LLRPC_GET_DATA(local, remote, size) ((void)(local), (void)(remote), (void)(size), -EFAULT)
# define CLICK_LLRPC_PUT_DATA(remote, local, size) ((void)(local), (void)(remote), (void)(size), -EFAULT)
# define CLICK_LLRPC_GET(local_obj, remote_addr) ((void)(local_obj), (void)(remote_addr), -EFAULT)
# define CLICK_LLRPC_PUT(remote_addr, local_obj) ((void)(local_obj), (void)(remote_addr), -EFAULT)
#endif
/* CLICK_NTOH_LLRPC: portable LLRPC numbers to host LLRPC numbers */
/* CLICK_HTON_LLRPC: host LLRPC numbers to portable LLRPC numbers */
/* both macros are only suitable for integer constants and the like */
#if _CLICK_IOC_VOID != _CLICK_NET_IOC_VOID || _CLICK_IOC_OUT != _CLICK_NET_IOC_OUT || _CLICK_IOC_IN != _CLICK_NET_IOC_IN
# define CLICK_LLRPC_NTOH(command) \
(((command) & _CLICK_NET_IOC_VOID ? _CLICK_IOC_VOID : 0) \
| ((command) & _CLICK_NET_IOC_OUT ? _CLICK_IOC_OUT : 0) \
| ((command) & _CLICK_NET_IOC_IN ? _CLICK_IOC_IN : 0) \
| ((command) & _CLICK_IOC_BASE_MASK))
# define CLICK_LLRPC_HTON(command) \
(((command) & _CLICK_IOC_VOID ? _CLICK_NET_IOC_VOID : 0) \
| ((command) & _CLICK_IOC_OUT ? _CLICK_NET_IOC_OUT : 0) \
| ((command) & _CLICK_IOC_IN ? _CLICK_NET_IOC_IN : 0) \
| ((command) & _CLICK_IOC_BASE_MASK))
#else
# define CLICK_LLRPC_NTOH(command) (command)
# define CLICK_LLRPC_HTON(command) (command)
#endif
/* sanity checks */
#ifdef __FreeBSD__
# if _CLICK_IOC_VOID != IOC_VOID || _CLICK_IOC_OUT != IOC_OUT || _CLICK_IOC_IN != IOC_IN
# error "bad _CLICK_IOC constants"
# endif
#endif
#endif

View File

@ -0,0 +1,82 @@
#ifndef CLICK_MACHINE_HH
#define CLICK_MACHINE_HH 1
#if CLICK_LINUXMODULE
# include <click/cxxprotect.h>
CLICK_CXX_PROTECT
# include <linux/threads.h>
# include <linux/sched.h>
# if defined(CONFIG_SMP) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
# define num_possible_cpus() smp_num_cpus
# endif
CLICK_CXX_UNPROTECT
# include <click/cxxunprotect.h>
#endif
/** @brief Compiler fence.
Prevents reordering of loads and stores by the compiler. Not intended to
synchronize the processor's caches. */
inline void
click_compiler_fence()
{
asm volatile("" : : : "memory");
}
/** @brief Compiler fence that relaxes the processor.
Use this in spinloops, for example. */
inline void
click_relax_fence()
{
#if CLICK_LINUXMODULE
cpu_relax();
#elif HAVE_MULTITHREAD && (defined(__i386__) || defined(__arch_um__) || defined(__x86_64__))
asm volatile("rep; nop" : : : "memory"); // equivalent to "pause"
#else
click_compiler_fence();
#endif
}
/** @brief Full memory fence. */
inline void
click_fence()
{
#if CLICK_LINUXMODULE
smp_mb();
#elif HAVE_MULTITHREAD && (defined(__i386__) || defined(__arch_um__) || defined(__x86_64__))
// GCC 4.2.1 on Mac has __sync_synchronize, but it doesn't work!
asm volatile("mfence" : : : "memory");
#elif HAVE_MULTITHREAD && HAVE___SYNC_SYNCHRONIZE
__sync_synchronize();
#else
click_compiler_fence();
#endif
}
/** @brief Read memory fence.
On x86, equivalent to click_compiler_fence(). */
inline void click_read_fence() {
#if CLICK_LINUXMODULE
smp_rmb();
#elif HAVE_MULTITHREAD && (defined(__i386__) || defined(__arch_um__) || defined(__x86_64__))
click_compiler_fence();
#else
click_fence();
#endif
}
/** @brief Write memory fence.
On x86, equivalent to click_compiler_fence(). */
inline void click_write_fence() {
#if CLICK_LINUXMODULE
smp_wmb();
#elif HAVE_MULTITHREAD && (defined(__i386__) || defined(__arch_um__) || defined(__x86_64__))
click_compiler_fence();
#else
click_fence();
#endif
}
#endif

View File

@ -0,0 +1,223 @@
// -*- c-basic-offset: 4; related-file-name: "../../lib/master.cc" -*-
#ifndef CLICK_MASTER_HH
#define CLICK_MASTER_HH
#include <click/router.hh>
#include <click/atomic.hh>
#if CLICK_USERLEVEL
# include <signal.h>
#endif
#if CLICK_NS
# include <click/simclick.h>
#endif
CLICK_DECLS
#define CLICK_DEBUG_MASTER 0
class Master { public:
Master(int nthreads);
~Master();
void use();
void unuse();
void block_all();
void unblock_all();
void pause();
inline void unpause();
bool paused() const { return _master_paused > 0; }
inline int nthreads() const;
inline RouterThread *thread(int id) const;
void wake_somebody();
#if CLICK_USERLEVEL
int add_signal_handler(int signo, Router *router, String handler);
int remove_signal_handler(int signo, Router *router, String handler);
void process_signals(RouterThread *thread);
static void signal_handler(int signo); // not really public
#endif
void kill_router(Router*);
#if CLICK_NS
void initialize_ns(simclick_node_t *simnode);
simclick_node_t *simnode() const { return _simnode; }
#endif
#if CLICK_DEBUG_MASTER || CLICK_DEBUG_SCHEDULING
String info() const;
#endif
#if CLICK_USERLEVEL
static volatile sig_atomic_t signals_pending;
#endif
private:
// THREADS
RouterThread **_threads;
int _nthreads;
// ROUTERS
Router *_routers;
int _refcount;
void register_router(Router*);
void prepare_router(Router*);
void run_router(Router*, bool foreground);
void unregister_router(Router*);
#if CLICK_LINUXMODULE
spinlock_t _master_lock;
struct task_struct *_master_lock_task;
int _master_lock_count;
#elif HAVE_MULTITHREAD
Spinlock _master_lock;
#endif
atomic_uint32_t _master_paused;
inline void lock_master();
inline void unlock_master();
void request_stop();
bool verify_stop(RouterThread* t);
#if CLICK_USERLEVEL
// SIGNALS
struct SignalInfo {
int signo;
Router *router;
String handler;
SignalInfo *next;
SignalInfo(int signo_, Router *router_, const String &handler_)
: signo(signo_), router(router_), handler(handler_), next() {
}
bool equals(int signo_, Router *router_, const String &handler_) const {
return signo == signo_ && router == router_ && handler == handler_;
}
};
SignalInfo *_siginfo;
sigset_t _sig_dispatching;
Spinlock _signal_lock;
#endif
#if CLICK_NS
simclick_node_t *_simnode;
#endif
Master(const Master&);
Master& operator=(const Master&);
friend class Task;
friend class RouterThread;
friend class Router;
};
inline int
Master::nthreads() const
{
return _nthreads - 1;
}
inline RouterThread*
Master::thread(int id) const
{
// return the requested thread, or the quiescent thread if there's no such
// thread
if (unsigned(id + 1) < unsigned(_nthreads))
return _threads[id + 1];
else
return _threads[0];
}
inline void
Master::wake_somebody()
{
_threads[1]->wake();
}
#if CLICK_USERLEVEL
inline void
RouterThread::run_signals()
{
if (Master::signals_pending)
_master->process_signals(this);
}
inline int
TimerSet::next_timer_delay(bool more_tasks, Timestamp &t) const
{
# if CLICK_NS
// The simulator should never block.
(void) more_tasks, (void) t;
return 0;
# else
if (more_tasks || Master::signals_pending)
return 0;
t = timer_expiry_steady_adjusted();
if (!t)
return -1; // block forever
else if (unlikely(Timestamp::warp_jumping())) {
Timestamp::warp_jump_steady(t);
return 0;
} else if ((t -= Timestamp::now_steady(), !t.is_negative())) {
t = t.warp_real_delay();
return 1;
} else
return 0;
# endif
}
#endif
inline void
Master::request_stop()
{
for (RouterThread **t = _threads; t != _threads + _nthreads; ++t)
(*t)->_stop_flag = true;
// ensure that at least one thread is awake to handle the stop event
wake_somebody();
}
inline void
Master::lock_master()
{
#if CLICK_LINUXMODULE
if (current != _master_lock_task) {
spin_lock(&_master_lock);
_master_lock_task = current;
} else
_master_lock_count++;
#elif HAVE_MULTITHREAD
_master_lock.acquire();
#endif
}
inline void
Master::unlock_master()
{
#if CLICK_LINUXMODULE
assert(current == _master_lock_task);
if (_master_lock_count == 0) {
_master_lock_task = 0;
spin_unlock(&_master_lock);
} else
_master_lock_count--;
#elif HAVE_MULTITHREAD
_master_lock.release();
#endif
}
inline void
Master::unpause()
{
_master_paused--;
}
inline Master *
Element::master() const
{
return _router->master();
}
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,203 @@
/* -*- related-file-name: "../../lib/md5.cc" -*-
Copyright (c) 2006-2007 Regents of the University of California
Altered for Click by Eddie Kohler. */
/*
Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
L. Peter Deutsch
ghost@aladdin.com
*/
/*
Independent implementation of MD5 (RFC 1321).
This code implements the MD5 Algorithm defined in RFC 1321, whose
text is available at
http://www.ietf.org/rfc/rfc1321.txt
The code is derived from the text of the RFC, including the test suite
(section A.5) but excluding the rest of Appendix A. It does not include
any code or documentation that is identified in the RFC as being
copyrighted.
The original and principal author of md5.h is L. Peter Deutsch
<ghost@aladdin.com>. Other authors are noted in the change history
that follows (in reverse chronological order):
2002-04-13 lpd Removed support for non-ANSI compilers; removed
references to Ghostscript; clarified derivation from RFC 1321;
now handles byte order either statically or dynamically.
1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
added conditionalization for C++ compilation from Martin
Purschke <purschke@bnl.gov>.
1999-05-03 lpd Original version.
*/
#ifndef CLICK_MD5_H
#define CLICK_MD5_H
#if CLICK_LINUXMODULE
# include <click/cxxprotect.h>
CLICK_CXX_PROTECT
# include <linux/err.h>
# include <linux/crypto.h>
# if HAVE_LINUX_ASM_SCATTERLIST_H
# include <asm/scatterlist.h>
# endif
# include <linux/scatterlist.h>
CLICK_CXX_UNPROTECT
# include <click/cxxunprotect.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
typedef struct hash_desc md5_state_t;
#else
typedef struct crypto_tfm *md5_state_t;
#endif
static inline int md5_init(md5_state_t *pms) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
pms->tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(pms->tfm))
return PTR_ERR(pms->tfm);
pms->flags = 0;
crypto_hash_init(pms);
return 0;
#else
*pms = crypto_alloc_tfm("md5", 0);
if (IS_ERR(*pms))
return PTR_ERR(*pms);
crypto_digest_init(*pms);
return 0;
#endif
}
static inline void md5_reinit(md5_state_t *pms) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
crypto_hash_init(pms);
#else
crypto_digest_init(*pms);
#endif
}
static inline void md5_append(md5_state_t *pms, const unsigned char *data, int nbytes) {
struct scatterlist sg;
if (likely(virt_addr_valid((unsigned long)data))) {
sg_init_one(&sg, const_cast<uint8_t *>(data), nbytes);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
crypto_hash_update(pms, &sg, nbytes);
#else
crypto_digest_update(*pms, &sg, 1);
#endif
} else {
while (nbytes > 0) {
int len = nbytes;
int off = offset_in_page(data);
if (off + len > (int)PAGE_SIZE)
len = PAGE_SIZE - off;
sg_init_table(&sg, 1);
sg_set_page(&sg, vmalloc_to_page(const_cast<uint8_t *>(data)), len, off);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
crypto_hash_update(pms, &sg, len);
#else
crypto_digest_update(*pms, &sg, 1);
#endif
data += len;
nbytes -= len;
}
}
}
static inline void md5_finish(md5_state_t *pms, unsigned char digest[16]) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
crypto_hash_final(pms, digest);
#else
crypto_digest_final(*pms, digest);
#endif
}
static inline void md5_free(md5_state_t *pms) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
crypto_free_hash(pms->tfm);
#else
crypto_free_tfm(*pms);
#endif
}
#else
/*
* This package supports both compile-time and run-time determination of CPU
* byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
* compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
* defined as non-zero, the code will be compiled to run only on big-endian
* CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
* run on either big- or little-endian CPUs, but will run slightly less
* efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
*/
typedef unsigned char md5_byte_t; /* 8-bit byte */
typedef uint32_t md5_word_t; /* 32-bit word */
/* Define the state of the MD5 Algorithm. */
typedef struct md5_state_s {
md5_word_t count[2]; /* message length in bits, lsw first */
md5_word_t abcd[4]; /* digest buffer */
md5_byte_t buf[64]; /* accumulate block */
} md5_state_t;
#ifdef __cplusplus
extern "C"
{
#endif
/* Initialize the algorithm. */
int md5_init(md5_state_t *pms);
/* Re-initialize the algorithm after a prior md5_init(). */
static inline void md5_reinit(md5_state_t *pms) {
md5_init(pms);
}
/* Append a string to the message. */
void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);
/* Finish the message and return the digest. */
#define MD5_DIGEST_SIZE 16
void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
/* Finish the message and return the digest in ASCII. DOES NOT write a
terminating NUL character.
If 'allow_at == 0', the digest uses characters [A-Za-z0-9_], and has
length between MD5_TEXT_DIGEST_SIZE and MD5_TEXT_DIGEST_MAX_SIZE.
If 'allow_at != 0', the digest uses characters [A-Za-z0-9_@], and has
length of exactly MD5_TEXT_DIGEST_SIZE.
Returns the number of characters written. Again, this will NOT include
a terminating NUL. */
#define MD5_TEXT_DIGEST_SIZE 22 /* min len */
#define MD5_TEXT_DIGEST_MAX_SIZE 26 /* max len if !allow_at */
int md5_finish_text(md5_state_t *pms, char *text_digest, int allow_at);
#define md5_free(pms) /* do nothing */
#ifdef __cplusplus
}
#endif
#endif
#endif

View File

@ -0,0 +1,528 @@
// -*- c-basic-offset: 4; related-file-name: "../../lib/nameinfo.cc" -*-
#ifndef CLICK_NAMEINFO_HH
#define CLICK_NAMEINFO_HH
#include <click/args.hh>
#include <click/straccum.hh>
CLICK_DECLS
class Element;
class NameDB;
class ErrorHandler;
class NameInfo { public:
/** @brief Construct a NameInfo element.
*
* Users never need to call this. */
NameInfo();
/** @brief Destroy a NameInfo object.
*
* Also destroys all NameDB objects installed on this NameInfo.
*
* Users never need to call this. */
~NameInfo();
/** @brief Static initialization for NameInfo.
*
* Creates the global NameInfo used for databases unconnected to any
* router. Users never need to call this. */
static void static_initialize();
/** @brief Static cleanup for NameInfo.
*
* Destroys the global NameInfo used for databases unconnected to any
* router. Users never need to call this. */
static void static_cleanup();
/** @brief Known name database types. */
enum DBType {
T_NONE = 0, ///< Nonexistent names database
T_SCHEDULEINFO = 0x00000001, ///< ScheduleInfo database
T_ANNOTATION = 0x00000002, ///< Packet annotation database
T_SCRIPT_INSN = 0x00000003, ///< Script instruction names database
T_SIGNO = 0x00000004, ///< User-level signal names database
T_SPINLOCK = 0x00000005, ///< Spinlock names database
T_ETHERNET_ADDR = 0x01000001, ///< Ethernet address names database
T_IP_ADDR = 0x04000001, ///< IP address names database
T_IP_PREFIX = 0x04000002, ///< IP prefix names database
T_IP_PROTO = 0x04000003, ///< IP protocol names database
T_IPFILTER_TYPE = 0x04000004, ///< IPFilter instruction names database
T_TCP_OPT = 0x04000005, ///< TCP option names database
T_IPREWRITER_PATTERN = 0x04000006, ///< IPRewriterPattern database
T_ICMP_TYPE = 0x04010000, ///< ICMP type names database
T_ICMP_CODE = 0x04010100, ///< ICMP code names database
T_IP_PORT = 0x04020000, ///< Starting point for IP per-protocol port names databases
T_TCP_PORT = 0x04020006, ///< TCP port names database
T_UDP_PORT = 0x04020011, ///< UDP port names database
T_IP_FIELDNAME = 0x04030000, ///< Starting point for IP per-protocol field names databases
T_ICMP_FIELDNAME = 0x04030001, ///< ICMP field names database
T_TCP_FIELDNAME = 0x04030006, ///< TCP field names database
T_UDP_FIELDNAME = 0x04030011, ///< UDP field names database
T_IP6_ADDR = 0x06000001, ///< IPv6 address names database
T_IP6_PREFIX = 0x06000002 ///< IPv6 prefix names database
};
/** @brief Find or create a name database.
* @param type database type
* @param context compound element context
* @param value_size size of values stored in database
* @param create whether to create a DynamicNameDB if no database exists
*
* Returns an installed name database matching @a type and @a context.
* (If @a context is non-null, then the database matches the implied
* router and compound element context. Otherwise, the database is the
* unique global database for the given @a type.) If @a create is true,
* and no database exists exactly matching @a type and @a context, then a
* DynamicNameDB is created and installed with that @a type, @a context,
* and @a value_size. Otherwise, the search bubbles up through the
* prefixes of @a context until an installed database is found.
*
* Returns null if no installed database is found. @a value_size must
* match the value size in the returned database.
*
* Most users will use query() and define() directly, not call getdb().
*/
static NameDB *getdb(uint32_t type, const Element *context,
size_t value_size, bool create);
/** @brief Install a name database.
* @param db name database
* @param context compound element context
*
* Installs the given name database for the compound element context
* implied by @a context. (If @a context is non-null, then the database
* is installed for the implied router and compound element context. If
* it is null, the database is installed globally.) The query() and
* define() operations apply only to installed databases.
*
* It is an error to install a database that has already been installed.
* It is also an error to install a database for a compound element
* context that already has a different database installed. An installed
* NameDB is automatically destroyed when its containing NameInfo is
* destroyed (for example, when @a context's router is destroyed).
*/
static void installdb(NameDB *db, const Element *context);
/** @brief Uninstall a name database.
* @param db name database
*
* Undoes the effects of installdb(). The given database will no longer
* be used for query() and define() operations.
*/
static void uninstalldb(NameDB *db);
/** @brief Query installed databases for @a name.
* @param type database type
* @param context compound element context
* @param name name to look up
* @param value_store value storage
* @param value_size size of value storage
* @return true iff the query succeeded
*
* Queries all installed @a type databases that apply to the compound
* element @a context, returning the most specific value matching @a name.
* The value is stored in @a value_store. The installed databases must
* have the given @a value_size.
*/
static bool query(uint32_t type, const Element *context,
const String &name, void *value_store, size_t value_size);
/** @brief Query installed databases for @a name, returning a 32-bit integer value.
* @param type database type
* @param context compound element context
* @param name name to look up
* @param value_store value storage
* @return true iff the query succeeded
*
* Queries all installed @a type databases that apply to the compound
* element @a context, returning the most specific value matching @a name.
* The value is stored in @a value_store. The installed databases must
* have a value size of 4.
*
* If no matching name is found, query_int checks whether @a name unparses
* into a 32-bit integer value (for example, "30"). If so, *@a
* value_store is set to the corresponding integer and true is returned.
* Otherwise, false is returned.
*/
static bool query_int(uint32_t type, const Element *context,
const String &name, int32_t *value_store);
/** @overload */
static bool query_int(uint32_t type, const Element *context,
const String &name, uint32_t *value_store);
/** @brief Query installed databases for @a value.
* @param type database type
* @param context compound element context
* @param value points to value to look up
* @param value_size size of value
* @return the name, or the empty string if the query failed
*
* Queries all installed @a type databases that apply to the compound
* element @a context, returning the name in the most specific database
* whose value matches @a value, or the empty string if the relevant
* databases don't support reverse queries or no such value exists. The
* installed databases must have the given @a value_size.
*/
static String revquery(uint32_t type, const Element *context,
const void *value, size_t value_size);
/** @brief Query installed databases for a 32-bit integer @a value.
* @param type database type
* @param context compound element context
* @param value value to look up
* @return the name, or the empty string if the query failed
*
* Queries all installed @a type databases that apply to the compound
* element @a context, returning the name in the most specific database
* whose value matches @a value, or the empty string if the relevant
* databases don't support reverse queries or no such value exists. The
* installed databases must have value size 4.
*/
static inline String revquery_int(uint32_t type, const Element *context,
int32_t value);
/** @brief Define @a name to equal @a value in the installed databases.
* @param type database type
* @param context compound element context
* @param name name to define
* @param value points to defined value
* @param value_size size of value
* @return true iff the name was defined
*
* Defines the given @a name to @a value in the installed @a type database
* with compound element @a context. If no database exists exactly
* matching that @a type and @a context, a new DynamicNameDB is created
* and installed with those values (and the given @a value_size). A name
* might not be defined if the existing database for that @a type and @a
* context doesn't support definitions, or if no new database can be
* created. If any database exists, it must match the given @a
* value_size.
*/
static inline bool define(uint32_t type, const Element *context,
const String &name, const void *value, size_t value_size);
/** @brief Define @a name to equal 32-bit integer @a value in the installed databases.
* @param type database type
* @param context compound element context
* @param name name to define
* @param value defined value
* @return true iff the value was defined
*
* Defines the given @a name to @a value in the installed @a type database
* with compound element @a context. If no database exists exactly
* matching that @a type and @a context, a new DynamicNameDB is created
* and installed with those values (and value size 4). A name might not
* be defined if the existing database for that @a type and @a context
* doesn't support definitions, or if no new database can be created. If
* any database exists, it must have value size 4.
*/
static inline bool define_int(uint32_t type, const Element *context,
const String &name, int32_t value);
#if CLICK_NAMEDB_CHECK
/** @cond never */
void check(ErrorHandler *);
static void check(const Element *, ErrorHandler *);
/** @endcond never */
#endif
private:
Vector<NameDB *> _namedb_roots;
Vector<NameDB *> _namedbs;
inline NameDB *install_dynamic_sentinel() { return (NameDB *) this; }
NameDB *namedb(uint32_t type, size_t size, const String &prefix, NameDB *installer);
#if CLICK_NAMEDB_CHECK
uintptr_t _check_generation;
void checkdb(NameDB *db, NameDB *parent, ErrorHandler *errh);
#endif
};
class NameDB { public:
/** @brief Construct a database.
* @param type database type
* @param context database compound element context, as a String
* @param value_size database value size
*
* @a value_size must be greater than 0. */
inline NameDB(uint32_t type, const String &context, size_t value_size);
/** @brief Destroy a database.
*
* Destroying an installed database automatically uninstalls it.
* See NameInfo::uninstalldb(). */
virtual ~NameDB() {
NameInfo::uninstalldb(this);
}
/** @brief Return the database type. */
uint32_t type() const {
return _type;
}
/** @brief Return the database's compound element context as a string. */
const String &context() const {
return _context;
}
/** @brief Return the contextual parent database, if any.
*
* The contextual parent database is the unique database, for the same
* router, with the same type(), whose context() is a prefix of this
* database's context(), that has the longest context() of any matching
* database. If there is no such database returns null. */
NameDB *context_parent() const {
return _context_parent;
}
/** @brief Return the database's value size. */
size_t value_size() const {
return _value_size;
}
/** @brief Query this database for a given name.
* @param name name to look up
* @param value points to value storage
* @param value_size size of value storage
* @return true iff the query succeeded
*
* The @a value_size parameter must equal this database's value size. */
virtual bool query(const String &name, void *value, size_t value_size) = 0;
/** @brief Query this database for a given value.
* @param value points to value to look up
* @param value_size size of value storage
* @return the name for the given value, or an empty string if the value
* has not been defined
*
* The @a value_size parameter must equal this database's value size.
* The default implementation always returns the empty string. */
virtual String revquery(const void *value, size_t value_size);
/** @brief Define a name in this database to a given value.
* @param name name to define
* @param value points to value to define
* @param value_size size of value storage
* @return true iff the name was defined
*
* The @a value_size parameter must equal this database's value size.
* The default implementation always returns false. */
virtual bool define(const String &name, const void *value, size_t value_size);
/** @brief Define a name in this database to a 32-bit integer value.
* @param name name to define
* @param value value to define
* @return true iff the name was defined
*
* The database's value size must equal 4. The implementation is the same
* as <code>define(name, &value, 4)</code>. */
inline bool define_int(const String &name, int32_t value);
#if CLICK_NAMEDB_CHECK
/** @cond never */
virtual void check(ErrorHandler *);
/** @endcond never */
#endif
private:
uint32_t _type;
String _context;
size_t _value_size;
NameDB *_context_parent;
NameDB *_context_sibling;
NameDB *_context_child;
NameInfo *_installed;
#if CLICK_NAMEDB_CHECK
uintptr_t _check_generation;
#endif
friend class NameInfo;
};
class StaticNameDB : public NameDB { public:
struct Entry {
const char *name;
uint32_t value;
};
/** @brief Construct a static name database.
* @param type database type
* @param context database compound element context, as a String
* @param entry pointer to static entry list
* @param nentry number of entries
*
* The entry array specifies the contents of the database. It must be
* sorted by name: entry[i].name < entry[i+1].name for all 0 <= i <
* nentry-1. The entry array must also persist as long as the database is
* in use; the database doesn't copy the entry array into its own memory,
* but continues to use the array passed in. The resulting database has
* value_size() 4. */
inline StaticNameDB(uint32_t type, const String &context,
const Entry *entry, size_t nentry);
/** @brief Query this database for a given name.
* @param name name to look up
* @param value points to value storage
* @param value_size size of value storage
* @return true iff the query succeeded
*
* The @a value_size parameter must equal 4. */
bool query(const String &name, void *value, size_t value_size);
/** @brief Query this database for a given value.
* @param value points to value to look up
* @param value_size size of value storage
* @return the name for the given value, or an empty string if the value
* has not been defined
*
* The @a value_size parameter must equal 4. */
String revquery(const void *value, size_t value_size);
#if CLICK_NAMEDB_CHECK
/** @cond never */
void check(ErrorHandler *);
/** @endcond never */
#endif
private:
const Entry *_entries;
size_t _nentries;
};
class DynamicNameDB : public NameDB { public:
/** @brief Construct a dynamic name database.
* @param type database type
* @param context database compound element context, as a String
* @param value_size database value size
*
* @a value_size must be greater than 0. The database is initially
* empty. */
inline DynamicNameDB(uint32_t type, const String &context, size_t value_size);
/** @brief Query this database for a given name.
* @param name name to look up
* @param value points to value storage
* @param value_size size of value storage
* @return true iff the query succeeded
*
* The @a value_size parameter must equal this database's value size. */
bool query(const String &name, void *value, size_t value_size);
/** @brief Query this database for a given value.
* @param value points to value to look up
* @param value_size size of value storage
* @return the name for the given value, or an empty string if the value
* has not been defined
*
* The @a value_size parameter must equal this database's value size. */
String revquery(const void *value, size_t value_size);
/** @brief Define a name in this database to a given value.
* @param name name to define
* @param value points to value to define
* @param value_size size of value storage
* @return true iff the name was defined
*
* The @a value_size parameter must equal this database's value size. */
bool define(const String &name, const void *value, size_t value_size);
#if CLICK_NAMEDB_CHECK
/** @cond never */
void check(ErrorHandler *);
/** @endcond never */
#endif
private:
Vector<String> _names;
StringAccum _values;
int _sorted;
void *find(const String &name, bool create);
void sort();
};
inline
NameDB::NameDB(uint32_t type, const String &context, size_t vsize)
: _type(type), _context(context), _value_size(vsize),
_context_parent(0), _context_sibling(0), _context_child(0), _installed(0)
{
#if CLICK_NAMEDB_CHECK
_check_generation = 0;
#endif
assert(_value_size > 0);
}
inline
StaticNameDB::StaticNameDB(uint32_t type, const String &context, const Entry *entry, size_t nentry)
: NameDB(type, context, sizeof(entry->value)), _entries(entry), _nentries(nentry)
{
}
inline
DynamicNameDB::DynamicNameDB(uint32_t type, const String &context, size_t vsize)
: NameDB(type, context, vsize), _sorted(0)
{
}
inline String
NameInfo::revquery_int(uint32_t type, const Element *e, int32_t value)
{
return revquery(type, e, &value, sizeof(value));
}
inline bool
NameInfo::define(uint32_t type, const Element *e, const String &name, const void *value, size_t vsize)
{
if (NameDB *db = getdb(type, e, vsize, true))
return db->define(name, value, vsize);
else
return false;
}
inline bool
NameInfo::define_int(uint32_t type, const Element *e, const String &name, const int32_t value)
{
if (NameDB *db = getdb(type, e, sizeof(value), true))
return db->define(name, &value, sizeof(value));
else
return false;
}
inline bool
NameDB::define_int(const String &name, const int32_t value)
{
return define(name, &value, sizeof(value));
}
/** @class NamedIntArg
@brief Parser class for named integers. */
struct NamedIntArg {
NamedIntArg(uint32_t type)
: _type(type) {
}
bool parse(const String &str, int &value, const ArgContext &args) {
return NameInfo::query(_type, args.context(), str,
&value, sizeof(value))
|| IntArg().parse(str, value, args);
}
int _type;
};
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,730 @@
// -*- c-basic-offset: 4; related-file-name: "../../lib/notifier.cc" -*-
#ifndef CLICK_NOTIFIER_HH
#define CLICK_NOTIFIER_HH
#include <click/task.hh>
#include <click/atomic.hh>
#include <click/algorithm.hh>
#if HAVE_CXX_PRAGMA_INTERFACE
# pragma interface "click/notifier.hh"
#endif
CLICK_DECLS
class NotifierSignal {
public:
typedef bool (NotifierSignal::*unspecified_bool_type)() const;
inline NotifierSignal();
inline NotifierSignal(atomic_uint32_t* value, uint32_t mask);
inline NotifierSignal(const NotifierSignal& x);
inline ~NotifierSignal();
static inline NotifierSignal idle_signal();
static inline NotifierSignal busy_signal();
static inline NotifierSignal overderived_signal();
static inline NotifierSignal uninitialized_signal();
inline bool active() const;
inline operator unspecified_bool_type() const;
inline bool set_active(bool active);
inline bool idle() const;
inline bool busy() const;
inline bool overderived() const;
inline bool initialized() const;
friend bool operator==(const NotifierSignal &a, const NotifierSignal &b);
friend bool operator!=(const NotifierSignal &a, const NotifierSignal &b);
NotifierSignal& operator=(const NotifierSignal& x);
NotifierSignal& operator+=(const NotifierSignal& x);
friend NotifierSignal operator+(NotifierSignal a, const NotifierSignal &b);
inline void swap(NotifierSignal& x);
String unparse(Router *router) const;
static void static_initialize();
private:
struct vmpair {
atomic_uint32_t *value;
uint32_t mask;
};
union vmvalue {
atomic_uint32_t *v1;
vmpair *vm;
};
vmvalue _v;
uint32_t _mask;
enum {
true_mask = 1, false_mask = 2, overderived_mask = 4,
uninitialized_mask = 8
};
static atomic_uint32_t static_value;
void hard_assign_vm(const NotifierSignal &x);
void hard_derive_one(atomic_uint32_t *value, uint32_t mask);
static bool hard_equals(const vmpair *a, const vmpair *b);
};
class Notifier { public:
enum SearchOp { SEARCH_STOP = 0, SEARCH_CONTINUE, SEARCH_CONTINUE_WAKE };
typedef void (*callback_type)(void *, Notifier *);
inline Notifier(SearchOp op = SEARCH_STOP);
inline Notifier(const NotifierSignal &signal, SearchOp op = SEARCH_STOP);
virtual ~Notifier();
/** @brief Return whether the Notifier is initialized. */
inline bool initialized() const {
return _signal.initialized();
}
int initialize(const char *name, Router *router);
inline const NotifierSignal &signal() const;
inline SearchOp search_op() const;
inline bool active() const;
inline bool set_active(bool active);
inline void wake();
inline void sleep();
virtual int add_activate_callback(callback_type f, void *user_data);
virtual void remove_activate_callback(callback_type f, void *user_data);
inline int add_listener(Task *task);
inline void remove_listener(Task *task);
inline int add_dependent_signal(NotifierSignal *signal);
inline void remove_dependent_signal(NotifierSignal *signal);
static const char EMPTY_NOTIFIER[];
static const char FULL_NOTIFIER[];
static inline NotifierSignal upstream_empty_signal(Element *e, int port);
static inline NotifierSignal upstream_empty_signal(Element *e, int port, Task *task);
static inline NotifierSignal upstream_empty_signal(Element *e, int port, Notifier *dependent_notifier);
static NotifierSignal upstream_empty_signal(Element *e, int port, callback_type f, void *user_data);
static inline NotifierSignal downstream_full_signal(Element *e, int port);
static inline NotifierSignal downstream_full_signal(Element *e, int port, Task *task);
static inline NotifierSignal downstream_full_signal(Element *e, int port, Notifier *dependent_notifier);
static NotifierSignal downstream_full_signal(Element *e, int port, callback_type f, void *user_data);
static inline NotifierSignal upstream_empty_signal(Element *e, int port, int) CLICK_DEPRECATED;
static inline NotifierSignal upstream_empty_signal(Element *e, int port, int, Notifier *) CLICK_DEPRECATED;
static inline NotifierSignal downstream_full_signal(Element *e, int port, int) CLICK_DEPRECATED;
static inline NotifierSignal downstream_full_signal(Element *e, int port, int, Notifier *) CLICK_DEPRECATED;
private:
NotifierSignal _signal;
SearchOp _search_op;
static void dependent_signal_callback(void *, Notifier *);
};
class ActiveNotifier : public Notifier { public:
ActiveNotifier(SearchOp op = SEARCH_STOP);
~ActiveNotifier();
int add_activate_callback(callback_type f, void *v);
void remove_activate_callback(callback_type f, void *v);
void listeners(Vector<Task*> &v) const CLICK_DEPRECATED;
inline void set_active(bool active, bool schedule = true);
inline void wake();
inline void sleep();
#if CLICK_DEBUG_SCHEDULING
String unparse(Router *router) const;
#endif
private:
typedef union {
Task *t;
callback_type f;
void *v;
uintptr_t p;
} task_or_signal_t;
Task* _listener1;
task_or_signal_t* _listeners;
int listener_add(callback_type f, void *v);
int listener_remove(callback_type f, void *v);
ActiveNotifier(const ActiveNotifier&); // does not exist
ActiveNotifier& operator=(const ActiveNotifier&); // does not exist
};
/** @brief Construct a busy signal.
*
* The returned signal is always active. */
inline NotifierSignal::NotifierSignal()
: _mask(true_mask) {
_v.v1 = &static_value;
}
/** @brief Construct an activity signal.
*
* Elements should not use this constructor directly.
* @sa Router::new_notifier_signal */
inline NotifierSignal::NotifierSignal(atomic_uint32_t* value, uint32_t mask)
: _mask(mask) {
_v.v1 = value;
}
/** @brief Copy construct a signal. */
inline NotifierSignal::NotifierSignal(const NotifierSignal& x)
: _mask(x._mask) {
if (likely(_mask))
_v.v1 = x._v.v1;
else
hard_assign_vm(x);
}
/** @brief Destroy a signal. */
inline NotifierSignal::~NotifierSignal() {
if (unlikely(_mask == 0))
delete[] _v.vm;
}
/** @brief Return an idle signal.
*
* The returned signal is never active. */
inline NotifierSignal NotifierSignal::idle_signal() {
return NotifierSignal(&static_value, false_mask);
}
/** @brief Return a busy signal.
*
* The returned signal is always active. */
inline NotifierSignal NotifierSignal::busy_signal() {
return NotifierSignal(&static_value, true_mask);
}
/** @brief Return an overderived busy signal.
*
* Overderived signals replace derived signals that are too complex to
* represent. An overderived signal, like a busy signal, is always
* active. */
inline NotifierSignal NotifierSignal::overderived_signal() {
return NotifierSignal(&static_value, overderived_mask | true_mask);
}
/** @brief Return an uninitialized signal.
*
* Uninitialized signals may be used occasionally as placeholders for true
* signals to be added later. Uninitialized signals are never active. */
inline NotifierSignal NotifierSignal::uninitialized_signal() {
return NotifierSignal(&static_value, uninitialized_mask);
}
/** @brief Test if the signal is active. */
inline bool NotifierSignal::active() const {
// 2012.May.16 This fence is necessary; consider, for example,
// InfiniteSource's checking of nonfull notifiers.
click_fence();
if (likely(_mask))
return (*_v.v1 & _mask) != 0;
else {
for (vmpair *vm = _v.vm; vm->mask; ++vm)
if ((*vm->value & vm->mask) != 0)
return true;
return false;
}
}
/** @brief Test if the signal is active. */
inline NotifierSignal::operator unspecified_bool_type() const {
return active() ? &NotifierSignal::active : 0;
}
/** @brief Test if the signal is idle.
* @return true iff the signal is idle, i.e. it will never be active. */
inline bool NotifierSignal::idle() const {
return (_mask == false_mask && _v.v1 == &static_value);
}
/** @brief Test if the signal is busy.
* @return true iff the signal is busy, i.e. it will always be active.
*
* @note An overderived_signal() is busy(), but a busy_signal() is not
* overderived(). */
inline bool NotifierSignal::busy() const {
return ((_mask & true_mask) && _v.v1 == &static_value);
}
/** @brief Test if the signal is overderived.
* @return true iff the signal equals overderived_signal().
*
* @note An overderived_signal() is busy(), but a busy_signal() is not
* overderived(). */
inline bool NotifierSignal::overderived() const {
return ((_mask & overderived_mask) && _v.v1 == &static_value);
}
/** @brief Test if the signal is initialized.
* @return true iff the signal doesn't equal uninitialized_signal(). */
inline bool NotifierSignal::initialized() const {
return (!(_mask & uninitialized_mask) || _v.v1 != &static_value);
}
/** @brief Set whether the basic signal is active.
* @param active true iff the basic signal is active
* @return previous active state
*
* Use this function to set whether a basic signal is active.
*
* It is illegal to call set_active() on derived, idle, busy, or
* overderived signals. Some of these actions may cause an assertion
* failure. */
inline bool NotifierSignal::set_active(bool active) {
assert(_v.v1 != &static_value && !(_mask & (_mask - 1)));
uint32_t expected = *_v.v1;
#if !CLICK_USERLEVEL || HAVE_MULTITHREAD
while (_mask) {
uint32_t desired = (active ? expected | _mask : expected & ~_mask);
uint32_t actual = _v.v1->compare_swap(expected, desired);
if (expected == actual)
break;
expected = actual;
}
#else
*_v.v1 = (active ? expected | _mask : expected & ~_mask);
#endif
return expected & _mask;
}
/** @brief Assign a signal. */
inline NotifierSignal& NotifierSignal::operator=(const NotifierSignal& x) {
if (likely(this != &x)) {
if (unlikely(_mask == 0))
delete[] _v.vm;
_mask = x._mask;
if (likely(_mask))
_v.v1 = x._v.v1;
else
hard_assign_vm(x);
}
return *this;
}
/** @brief Exchange the values of this signal and @a x. */
inline void NotifierSignal::swap(NotifierSignal& x) {
click_swap(_v, x._v);
click_swap(_mask, x._mask);
}
/** @relates NotifierSignal
* @brief Test if two NotifierSignals are equal.
*
* Returns true iff the two NotifierSignals are the same -- i.e., they
* combine information about exactly the same sets of basic signals.
*
* All idle() signals compare equal. busy_signal() and
* overderived_signal() do not compare equal, however. */
inline bool operator==(const NotifierSignal& a, const NotifierSignal& b) {
if (a._mask == b._mask) {
if (likely(a._mask))
return a._v.v1 == b._v.v1;
else
return NotifierSignal::hard_equals(a._v.vm, b._v.vm);
} else
return false;
}
/** @relates NotifierSignal
* @brief Test if two NotifierSignals are unequal.
*
* Returns true iff !(@a a == @a b). */
inline bool operator!=(const NotifierSignal& a, const NotifierSignal& b) {
return !(a == b);
}
/** @relates NotifierSignal
* @brief Return a derived signal.
*
* Returns a derived signal that combines information from its arguments.
* The result will be active whenever @a a and/or @a b is active. If the
* combination of @a a and @a b is too complex to represent, returns an
* overderived signal; this trivially follows the invariant since it is
* always active.
*
* Signal derivation is commutative and associative. The following
* special combinations are worth remembering:
*
* - An uninitialized signal plus any other signal is uninitialized.
* - An idle signal plus any signal @a a equals @a a.
* - A busy signal plus any other initialized signal is busy.
* - overderived_signal() plus busy_signal() equals busy_signal().
*
* @sa NotifierSignal::operator+= */
inline NotifierSignal operator+(NotifierSignal a, const NotifierSignal& b) {
return a += b;
}
/** @brief Constructs a Notifier.
* @param op controls notifier path search
*
* This function constructs a Notifier object. The Notifier's associated
* NotifierSignal is initially idle; it becomes associated with a signal after
* initialize() is called.
*
* The @a op argument controls path search. The rest of this entry
* describes it further.
*
* Elements interested in notification generally search for Notifier objects
* along all possible packet paths upstream (or downstream) of one of their
* ports. When a Notifier is found along a path, further searching along that
* path is cut off, so only the closest Notifiers are found. Sometimes,
* however, it makes more sense to continue searching for more Notifiers. The
* correct behavior is Notifier-specific, and is controlled by this method.
* When the search encounters a Notifier, it consults the Notifier's @a
* op variable supplied to the constructor. It should equal one of
* three SearchOp constants, which correspond to the following behavior:
*
* <dl>
* <dt>SEARCH_STOP</dt>
* <dd>Stop searching along this path. This is the default.</dd>
* <dt>SEARCH_CONTINUE</dt>
* <dd>Continue searching along this path.</dd>
* <dt>SEARCH_CONTINUE_WAKE</dt>
* <dd>Continue searching along this path, but any further Notifiers should
* only be used for adding and removing listeners; ignore their NotifierSignal
* objects. This operation is useful, for example, for schedulers that store
* packets temporarily. Such schedulers provide their own NotifierSignal,
* since the scheduler may still hold a packet even when all upstream sources
* are empty, but since they aren't packet sources, they don't know when
* new packets arrive and can't wake up sleeping listeners. During
* initialization, such schedulers should call Notifier::upstream_empty_signal,
* passing their own Notifier as the fourth argument. This will ensure that
* their signal is turned on appropriately whenever an upstream queue becomes
* nonempty.</dd>
* </dl>
*/
inline Notifier::Notifier(SearchOp op)
: _signal(NotifierSignal::uninitialized_signal()), _search_op(op) {
}
/** @brief Constructs a Notifier associated with a given signal.
* @param signal the associated NotifierSignal
* @param op controls notifier path search
*
* This function constructs a Notifier object associated with a specific
* NotifierSignal, such as NotifierSignal::idle_signal(). Calling
* initialize() on this Notifier will not change the associated
* NotifierSignal. The @a op argument is as in
* Notifier::Notifier(SearchOp), above.
*/
inline Notifier::Notifier(const NotifierSignal &signal, SearchOp op)
: _signal(signal), _search_op(op) {
}
/** @brief Return this Notifier's associated NotifierSignal.
*
* Every Notifier object corresponds to one NotifierSignal; this method
* returns it. The signal is @link NotifierSignal::idle idle() @endlink
* before initialize() is called.
*/
inline const NotifierSignal& Notifier::signal() const {
return _signal;
}
/** @brief Return this Notifier's search operation.
*
* @sa Notifier() for a detailed explanation of search operations.
*/
inline Notifier::SearchOp Notifier::search_op() const {
return _search_op;
}
/** @brief Returns whether the associated signal is active.
*
* Same as signal().active().
*/
inline bool Notifier::active() const {
return _signal.active();
}
/** @brief Set the associated signal's activity.
* @param active true iff the signal should be active
* @return previous active state
*/
inline bool Notifier::set_active(bool active) {
return _signal.set_active(active);
}
/** @brief Set the associated signal to active.
* @sa set_active
*/
inline void Notifier::wake() {
set_active(true);
}
/** @brief Set the associated signal to inactive.
* @sa set_active
*/
inline void Notifier::sleep() {
set_active(false);
}
/** @brief Register a listener with this Notifier.
* @param task Task to reschedule when this Notifier becomes active
*
* When this Notifier's associated signal is activated, the Notifier should
* schedule @a task. Not all types of Notifier provide this functionality. The
* default implementation does nothing.
*
* @sa remove_listener, add_activate_callback, add_dependent_signal
*/
inline int Notifier::add_listener(Task* task) {
return add_activate_callback(0, task);
}
/** @brief Unregister a listener with this Notifier.
* @param task listener Task
*
* Undoes the effect of all prior add_listener(@a task) calls. Does nothing if
* @a task was never added. The default implementation does nothing.
*
* @sa add_listener
*/
inline void Notifier::remove_listener(Task* task) {
remove_activate_callback(0, task);
}
/** @brief Register a dependent signal with this Notifier.
* @param signal dependent signal
*
* When this Notifier's associated signal is activated, the Notifier should
* also activate @a signal. Not all types of Notifier provide this
* functionality. The default implementation does nothing.
*
* @sa add_listener, add_activate_callback, remove_dependent_signal
*/
inline int Notifier::add_dependent_signal(NotifierSignal* signal) {
return add_activate_callback(dependent_signal_callback, signal);
}
/** @brief Unregister a dependent signal with this Notifier.
* @param signal dependent signal
*
* Undoes the effect of all prior add_dependent_signal(@a signal) calls. Does
* nothing if @a signal was never added. The default implementation does
* nothing.
*
* @sa add_dependent_signal
*/
inline void Notifier::remove_dependent_signal(NotifierSignal* signal) {
remove_activate_callback(dependent_signal_callback, signal);
}
/** @brief Calculate and return the NotifierSignal derived from all empty
* notifiers upstream of element @a e's input @a port.
* @param e an element
* @param port the input port of @a e at which to start the upstream search
*
* Searches the configuration upstream of element @a e's input @a port for @e
* empty @e notifiers. These notifiers are associated with packet storage,
* and should be true when packets are available (or likely to be available
* quite soon), and false when they are not. All notifiers found are combined
* into a single derived signal. Thus, if any of the base notifiers are
* active, indicating that at least one packet is available upstream, the
* derived signal will also be active. Element @a e's code generally uses the
* resulting signal to decide whether or not to reschedule itself.
*
* The returned signal is generally conservative, meaning that the signal
* is true whenever a packet exists upstream, but the elements that provide
* notification are responsible for ensuring this.
*
* Overloaded versions of this function can also register a task (as in
* add_listener()), a signal (as in add_dependent_notifier()), or a callback
* function (as in add_active_callback()) for each located notifier. When
* packets become available, the task will be scheduled, the signal will be
* activated, or the callback will be called.
*
* <h3>Supporting upstream_empty_signal()</h3>
*
* Elements that have an empty notifier must override the Element::cast()
* method. When passed the @a name Notifier::EMPTY_NOTIFIER, this method
* should return a pointer to the corresponding Notifier object.
*
* @sa downstream_full_signal
*/
inline NotifierSignal Notifier::upstream_empty_signal(Element* e, int port) {
return upstream_empty_signal(e, port, (callback_type) 0, 0);
}
/** @brief Calculate and return the NotifierSignal derived from all empty
* notifiers upstream of element @a e's input @a port.
* @param e an element
* @param port the input port of @a e at which to start the upstream search
* @param task task to schedule when packets become available
* @sa add_listener */
inline NotifierSignal Notifier::upstream_empty_signal(Element* e, int port,
Task* task) {
return upstream_empty_signal(e, port, (callback_type) 0, task);
}
/** @brief Calculate and return the NotifierSignal derived from all empty
* notifiers upstream of element @a e's input @a port.
* @param e an element
* @param port the input port of @a e at which to start the upstream search
* @param notifier notifier to activate when packets become available
* @sa add_dependent_signal */
inline NotifierSignal Notifier::upstream_empty_signal(Element* e, int port,
Notifier* dependent_notifier) {
return upstream_empty_signal(e, port, dependent_signal_callback, &dependent_notifier->_signal);
}
/** @brief Calculate and return the NotifierSignal derived from all full
* notifiers downstream of element @a e's output @a port.
* @param e an element
* @param port the output port of @a e at which to start the downstream search
*
* Searches the configuration downstream of element @a e's output @a port for
* @e full @e notifiers. These notifiers are associated with packet storage,
* and should be true when there is space for at least one packet, and false
* when there is not. All notifiers found are combined into a single derived
* signal. Thus, if any of the base notifiers are active, indicating that at
* least one path has available space, the derived signal will also be active.
* Element @a e's code generally uses the resulting signal to decide whether
* or not to reschedule itself.
*
* Overloaded versions of this function can also register a task (as in
* add_listener()), a signal (as in add_dependent_notifier()), or a callback
* function (as in add_active_callback()) for each located notifier. When
* space becomes available, the task will be scheduled, the signal will be
* activated, or the callback will be called.
*
* In current Click, the returned signal is conservative: if it's inactive,
* then there is no space for packets downstream.
*
* <h3>Supporting downstream_full_signal()</h3>
*
* Elements that have a full notifier must override the Element::cast()
* method. When passed the @a name Notifier::FULL_NOTIFIER, this method
* should return a pointer to the corresponding Notifier object.
*
* @sa upstream_empty_signal
*/
inline NotifierSignal Notifier::downstream_full_signal(Element* e, int port) {
return downstream_full_signal(e, port, (callback_type) 0, 0);
}
/** @brief Calculate and return the NotifierSignal derived from all full
* notifiers downstream of element @a e's output @a port.
* @param e an element
* @param port the output port of @a e at which to start the downstream search
* @param task task to schedule when packets become available
* @sa add_listener */
inline NotifierSignal Notifier::downstream_full_signal(Element* e, int port,
Task* task) {
return downstream_full_signal(e, port, (callback_type) 0, task);
}
/** @brief Calculate and return the NotifierSignal derived from all full
* notifiers downstream of element @a e's output @a port.
* @param e an element
* @param port the output port of @a e at which to start the downstream search
* @param notifier notifier to activate when packets become available
* @sa add_dependent_signal */
inline NotifierSignal Notifier::downstream_full_signal(Element* e, int port,
Notifier* dependent_notifier) {
return downstream_full_signal(e, port, dependent_signal_callback, &dependent_notifier->_signal);
}
/** @cond never */
inline NotifierSignal Notifier::upstream_empty_signal(Element* e, int port, int x) {
(void) x;
assert(x == 0);
return upstream_empty_signal(e, port);
}
inline NotifierSignal Notifier::upstream_empty_signal(Element* e, int port, int x,
Notifier* notifier) {
(void) x;
assert(x == 0);
return upstream_empty_signal(e, port, notifier);
}
inline NotifierSignal Notifier::downstream_full_signal(Element* e, int port, int x) {
(void) x;
assert(x == 0);
return downstream_full_signal(e, port);
}
inline NotifierSignal Notifier::downstream_full_signal(Element* e, int port, int x,
Notifier* notifier) {
(void) x;
assert(x == 0);
return downstream_full_signal(e, port, notifier);
}
/** @endcond never */
/** @brief Set the associated signal's activity, possibly scheduling any
* listener tasks.
* @param active true iff the signal should be active
* @param schedule if true, wake up listener tasks
*
* If @a active and @a schedule are both true, and the signal was previously
* inactive, then any listener Tasks are scheduled with Task::reschedule().
*
* @sa wake, sleep, add_listener
*/
inline void ActiveNotifier::set_active(bool active, bool schedule) {
bool was_active = Notifier::set_active(active);
if (active && schedule && !was_active) {
// 2007.Sep.6: Perhaps there was a race condition here. Make sure
// that we set the notifier to active BEFORE rescheduling downstream
// tasks. This is because, in a multithreaded environment, a task we
// reschedule might run BEFORE we set the notifier; after which it
// would go to sleep forever.
if (_listener1)
_listener1->reschedule();
else if (task_or_signal_t *tos = _listeners) {
for (; tos->p > 1; tos++)
tos->t->reschedule();
if (tos->p == 1)
for (tos++; tos->p; tos += 2)
tos->f(tos[1].v, this);
}
}
}
/** @brief Set the associated signal to active and schedule any listener
* tasks.
*
* If the signal was previously inactive, then any listener Tasks are
* scheduled with Task::reschedule().
*
* @sa set_active, add_listener
*/
inline void ActiveNotifier::wake() {
set_active(true, true);
}
/** @brief Set the associated signal to inactive.
* @sa set_active
*/
inline void ActiveNotifier::sleep() {
set_active(false, true);
}
inline void click_swap(NotifierSignal& x, NotifierSignal& y) {
x.swap(y);
}
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,30 @@
#ifndef CLICK_PACKAGE_HH
#define CLICK_PACKAGE_HH
#include <click/vector.hh>
#include <click/string.hh>
CLICK_DECLS
#ifndef CLICK_TOOL
class Element;
#endif
CLICK_ENDDECLS
extern "C" {
void click_provide(const char *);
void click_unprovide(const char *);
bool click_has_provision(const char *);
void click_public_packages(CLICK_NAME(Vector)<CLICK_NAME(String)> &);
#if CLICK_LINUXMODULE
int click_add_element_type(const char *element_name, CLICK_NAME(Element) *(*factory)(uintptr_t thunk), uintptr_t thunk, struct module *);
int click_add_element_type_stable(const char *element_name, CLICK_NAME(Element) *(*factory)(uintptr_t thunk), uintptr_t thunk, struct module *);
void click_remove_element_type(int);
#elif !CLICK_TOOL
int click_add_element_type(const char *element_name, CLICK_NAME(Element) *(*factory)(uintptr_t thunk), uintptr_t thunk);
int click_add_element_type_stable(const char *element_name, CLICK_NAME(Element) *(*factory)(uintptr_t thunk), uintptr_t thunk);
void click_remove_element_type(int);
#endif
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,137 @@
#ifndef CLICK_PACKET_ANNO_HH
#define CLICK_PACKET_ANNO_HH
#define MAKE_ANNOTATIONINFO(offset, size) ((size) << 16 | (offset))
#define ANNOTATIONINFO_SIZE(ai) ((ai) >> 16)
#define ANNOTATIONINFO_OFFSET(ai) ((uint16_t) (ai))
#define DST_IP_ANNO_OFFSET 0
#define DST_IP_ANNO_SIZE 4
#define DST_IP6_ANNO_OFFSET 0
#define DST_IP6_ANNO_SIZE 16
// bytes 16-31
#define WIFI_EXTRA_ANNO_OFFSET 16
#define WIFI_EXTRA_ANNO_SIZE 24
#define WIFI_EXTRA_ANNO(p) ((click_wifi_extra *) ((p)->anno_u8() + WIFI_EXTRA_ANNO_OFFSET))
// byte 16
#define PAINT_ANNO_OFFSET 16
#define PAINT_ANNO_SIZE 1
#define PAINT_ANNO(p) ((p)->anno_u8(PAINT_ANNO_OFFSET))
#define SET_PAINT_ANNO(p, v) ((p)->set_anno_u8(PAINT_ANNO_OFFSET, (v)))
// byte 17
#define ICMP_PARAMPROB_ANNO_OFFSET 17
#define ICMP_PARAMPROB_ANNO_SIZE 1
#define ICMP_PARAMPROB_ANNO(p) ((p)->anno_u8(ICMP_PARAMPROB_ANNO_OFFSET))
#define SET_ICMP_PARAMPROB_ANNO(p, v) ((p)->set_anno_u8(ICMP_PARAMPROB_ANNO_OFFSET, (v)))
// byte 19
#define FIX_IP_SRC_ANNO_OFFSET 19
#define FIX_IP_SRC_ANNO_SIZE 1
#define FIX_IP_SRC_ANNO(p) ((p)->anno_u8(FIX_IP_SRC_ANNO_OFFSET))
#define SET_FIX_IP_SRC_ANNO(p, v) ((p)->set_anno_u8(FIX_IP_SRC_ANNO_OFFSET, (v)))
// bytes 20-21
#define VLAN_TCI_ANNO_OFFSET 20
#define VLAN_TCI_ANNO_SIZE 2
#define VLAN_TCI_ANNO(p) ((p)->anno_u16(VLAN_TCI_ANNO_OFFSET))
#define SET_VLAN_TCI_ANNO(p, v) ((p)->set_anno_u16(VLAN_TCI_ANNO_OFFSET, (v)))
// bytes 20-23
#define AGGREGATE_ANNO_OFFSET 20
#define AGGREGATE_ANNO_SIZE 4
#define AGGREGATE_ANNO(p) ((p)->anno_u32(AGGREGATE_ANNO_OFFSET))
#define SET_AGGREGATE_ANNO(p, v) ((p)->set_anno_u32(AGGREGATE_ANNO_OFFSET, (v)))
#define FWD_RATE_ANNO_OFFSET 20
#define FWD_RATE_ANNO_SIZE 4
#define FWD_RATE_ANNO(p) ((p)->anno_s32(FWD_RATE_ANNO_OFFSET))
#define SET_FWD_RATE_ANNO(p, v) ((p)->set_anno_s32(FWD_RATE_ANNO_OFFSET, (v)))
#define MISC_IP_ANNO_OFFSET 20
#define MISC_IP_ANNO_SIZE 4
#define MISC_IP_ANNO(p) ((p)->anno_u32(MISC_IP_ANNO_OFFSET))
#define SET_MISC_IP_ANNO(p, v) ((p)->set_anno_u32(MISC_IP_ANNO_OFFSET, (v).addr()))
// bytes 24-27
#define EXTRA_PACKETS_ANNO_OFFSET 24
#define EXTRA_PACKETS_ANNO_SIZE 4
#define EXTRA_PACKETS_ANNO(p) ((p)->anno_u32(EXTRA_PACKETS_ANNO_OFFSET))
#define SET_EXTRA_PACKETS_ANNO(p, v) ((p)->set_anno_u32(EXTRA_PACKETS_ANNO_OFFSET, (v)))
#define REV_RATE_ANNO_OFFSET 24
#define REV_RATE_ANNO_SIZE 4
#define REV_RATE_ANNO(p) ((p)->anno_s32(REV_RATE_ANNO_OFFSET))
#define SET_REV_RATE_ANNO(p, v) ((p)->set_anno_s32(REV_RATE_ANNO_OFFSET, (v)))
// byte 26
#define SEND_ERR_ANNO_OFFSET 26
#define SEND_ERR_ANNO_SIZE 1
#define SEND_ERR_ANNO(p) ((p)->anno_u8(SEND_ERR_ANNO_OFFSET))
#define SET_SEND_ERR_ANNO(p, v) ((p)->set_anno_u8(SEND_ERR_ANNO_OFFSET, (v)))
// byte 27
#define GRID_ROUTE_CB_ANNO_OFFSET 27
#define GRID_ROUTE_CB_ANNO_SIZE 1
#define GRID_ROUTE_CB_ANNO(p) ((p)->anno_u8(GRID_ROUTE_CB_ANNO_OFFSET))
#define SET_GRID_ROUTE_CB_ANNO(p, v) ((p)->set_anno_u8(GRID_ROUTE_CB_ANNO_OFFSET, (v)))
// bytes 28-31
#define IPREASSEMBLER_ANNO_OFFSET 28
#define IPREASSEMBLER_ANNO_SIZE 4
#define EXTRA_LENGTH_ANNO_OFFSET 28
#define EXTRA_LENGTH_ANNO_SIZE 4
#define EXTRA_LENGTH_ANNO(p) ((p)->anno_u32(EXTRA_LENGTH_ANNO_OFFSET))
#define SET_EXTRA_LENGTH_ANNO(p, v) ((p)->set_anno_u32(EXTRA_LENGTH_ANNO_OFFSET, (v)))
// bytes 32-39
#define FIRST_TIMESTAMP_ANNO_OFFSET 32
#define FIRST_TIMESTAMP_ANNO_SIZE 8
#define CONST_FIRST_TIMESTAMP_ANNO(p) (*(reinterpret_cast<const Timestamp *>((p)->anno_u8() + FIRST_TIMESTAMP_ANNO_OFFSET)))
#define FIRST_TIMESTAMP_ANNO(p) (*(reinterpret_cast<Timestamp *>((p)->anno_u8() + FIRST_TIMESTAMP_ANNO_OFFSET)))
#define SET_FIRST_TIMESTAMP_ANNO(p, v) (*(reinterpret_cast<Timestamp *>((p)->anno_u8() + FIRST_TIMESTAMP_ANNO_OFFSET)) = (v))
// bytes 32-35
#define PACKET_NUMBER_ANNO_OFFSET 32
#define PACKET_NUMBER_ANNO_SIZE 4
#define PACKET_NUMBER_ANNO(p) ((p)->anno_u32(PACKET_NUMBER_ANNO_OFFSET))
#define SET_PACKET_NUMBER_ANNO(p, v) ((p)->set_anno_u32(PACKET_NUMBER_ANNO_OFFSET, (v)))
#define IPSEC_SPI_ANNO_OFFSET 32
#define IPSEC_SPI_ANNO_SIZE 4
#define IPSEC_SPI_ANNO(p) ((p)->anno_u32(IPSEC_SPI_ANNO_OFFSET))
#define SET_IPSEC_SPI_ANNO(p, v) ((p)->set_anno_u32(IPSEC_SPI_ANNO_OFFSET, (v)))
// bytes 36-39
#define SEQUENCE_NUMBER_ANNO_OFFSET 36
#define SEQUENCE_NUMBER_ANNO_SIZE 4
#define SEQUENCE_NUMBER_ANNO(p) ((p)->anno_u32(SEQUENCE_NUMBER_ANNO_OFFSET))
#define SET_SEQUENCE_NUMBER_ANNO(p, v) ((p)->set_anno_u32(SEQUENCE_NUMBER_ANNO_OFFSET, (v)))
#if SIZEOF_VOID_P == 4
# define IPSEC_SA_DATA_REFERENCE_ANNO_OFFSET 36
# define IPSEC_SA_DATA_REFERENCE_ANNO_SIZE 4
# define IPSEC_SA_DATA_REFERENCE_ANNO(p) ((p)->anno_u32(IPSEC_SA_DATA_REFERENCE_ANNO_OFFSET))
# define SET_IPSEC_SA_DATA_REFERENCE_ANNO(p, v) ((p)->set_anno_u32(IPSEC_SA_DATA_REFERENCE_ANNO_OFFSET, (v)))
#endif
#if HAVE_INT64_TYPES
// bytes 40-47
# define PERFCTR_ANNO_OFFSET 40
# define PERFCTR_ANNO_SIZE 8
# define PERFCTR_ANNO(p) ((p)->anno_u64(PERFCTR_ANNO_OFFSET))
# define SET_PERFCTR_ANNO(p, v) ((p)->set_anno_u64(PERFCTR_ANNO_OFFSET, (v)))
# if SIZEOF_VOID_P == 8
# define IPSEC_SA_DATA_REFERENCE_ANNO_OFFSET 40
# define IPSEC_SA_DATA_REFERENCE_ANNO_SIZE 8
# define IPSEC_SA_DATA_REFERENCE_ANNO(p) ((p)->anno_u64(IPSEC_SA_DATA_REFERENCE_ANNO_OFFSET))
# define SET_IPSEC_SA_DATA_REFERENCE_ANNO(p, v) ((p)->set_anno_u64(IPSEC_SA_DATA_REFERENCE_ANNO_OFFSET, (v)))
# endif
#endif
#endif

View File

@ -0,0 +1,89 @@
// -*- c-basic-offset: 4 -*-
#ifndef CLICK_PAIR_HH
#define CLICK_PAIR_HH
#include <click/hashcode.hh>
#include <click/type_traits.hh>
CLICK_DECLS
template <class T, class U>
struct Pair {
typedef T first_type;
typedef U second_type;
typedef T key_type;
typedef const T &key_const_reference;
T first;
U second;
inline Pair()
: first(), second() {
}
inline Pair(typename fast_argument<T>::type t,
typename fast_argument<U>::type u)
: first(t), second(u) {
}
inline Pair(const Pair<T, U> &p)
: first(p.first), second(p.second) {
}
template <typename V, typename W>
inline Pair(const Pair<V, W> &p)
: first(p.first), second(p.second) {
}
typedef hashcode_t (Pair<T, U>::*unspecified_bool_type)() const;
inline operator unspecified_bool_type() const {
return first || second ? &Pair<T, U>::hashcode : 0;
}
inline const T &hashkey() const {
return first;
}
inline hashcode_t hashcode() const;
template <typename V, typename W>
Pair<T, U> &operator=(const Pair<V, W> &p) {
first = p.first;
second = p.second;
return *this;
}
};
template <class T, class U>
inline bool operator==(const Pair<T, U> &a, const Pair<T, U> &b)
{
return a.first == b.first && a.second == b.second;
}
template <class T, class U>
inline bool operator!=(const Pair<T, U> &a, const Pair<T, U> &b)
{
return a.first != b.first || a.second != b.second;
}
template <class T, class U>
inline bool operator<(const Pair<T, U> &a, const Pair<T, U> &b)
{
return a.first < b.first
|| (!(b.first < a.first) && a.second < b.second);
}
template <class T, class U>
inline hashcode_t Pair<T, U>::hashcode() const
{
return (CLICK_NAME(hashcode)(first) << 7) ^ CLICK_NAME(hashcode)(second);
}
template <class T, class U>
inline Pair<T, U> make_pair(T t, U u)
{
return Pair<T, U>(t, u);
}
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,42 @@
/* include/click/pathvars.h. Generated from pathvars.h.in by configure. */
/* Process this file with configure to produce pathvars.h. -*- mode: c -*- */
#ifndef CLICK_PATHVARS_H
#define CLICK_PATHVARS_H
/* Install directory for Click executables. */
#define CLICK_BINDIR "/usr/local/bin"
/* Install directory for Click libraries and packages. */
#define CLICK_LIBDIR "/usr/local/lib"
/* Install directory for Click shared data. */
#define CLICK_DATADIR "/usr/local/share/click"
/* FreeBSD kernel include directory. */
#define FREEBSD_INCLUDEDIR "/usr/include"
/* Define if the BSD kernel module driver was compiled. */
/* #undef HAVE_BSDMODULE_DRIVER */
/* Define if the Click kernel module should provide clickfs. */
#define HAVE_CLICKFS 1
/* Define if the expat library is available. */
#define HAVE_EXPAT 1
/* Define if the Click linuxmodule is compiled for a 2.6 kernel. */
/* #undef HAVE_LINUXMODULE_2_6 */
/* Define if the Linux kernel module driver was compiled. */
/* #undef HAVE_LINUXMODULE_DRIVER */
/* Define if the minios driver was compiled. */
/* #undef HAVE_MINIOS_DRIVER */
/* Define if the user-level driver was compiled. */
#define HAVE_USERLEVEL_DRIVER 1
/* Directory containing Linux sources. */
#define LINUX_SRCDIR "NONE"
#endif

View File

@ -0,0 +1,37 @@
#ifndef CLICK_PERFCTR_HH
#define CLICK_PERFCTR_HH
#ifdef __KERNEL__
# include <click/glue.hh>
# include <click/cxxprotect.h>
CLICK_CXX_PROTECT
# include <asm/msr.h>
CLICK_CXX_UNPROTECT
# include <click/cxxunprotect.h>
#endif
#define DCU_MISS_OUTSTANDING 0x48
#define INST_RETIRED 0xC0
#define IFU_FETCH 0x80
#define IFU_FETCH_MISS 0x81
#define IFU_MEM_STALL 0x86
#define L2_LINES_IN 0x24
#define L2_LINES_OUT 0x26
#define L2_IFETCH 0x28 | (0xF<<8)
#define L2_LD 0x29 | (0xF<<8)
#define L2_LINES_OUTM 0x27
#define L2_RQSTS 0x2E | (0xF<<8)
#define BUS_LOCK_CLOCKS 0x63
#define BUS_TRAN_RFO 0x66
#define BUS_TRAN_INVAL 0x69
#define BUS_TRAN_MEM 0x6F
#define MSR_OS (1<<17)
#define MSR_OCCURRENCE (1<<18)
#define MSR_ENABLE (1<<22)
#define MSR_FLAGS0 (MSR_OS|MSR_OCCURRENCE|MSR_ENABLE)
#define MSR_FLAGS1 (MSR_OS|MSR_OCCURRENCE)
#define MSR_EVNTSEL0 0x186
#define MSR_EVNTSEL1 0x187
#endif

View File

@ -0,0 +1,624 @@
// -*- c-basic-offset: 4; related-file-name: "../../lib/router.cc" -*-
#ifndef CLICK_ROUTER_HH
#define CLICK_ROUTER_HH
#include <click/element.hh>
#include <click/timer.hh>
#include <click/sync.hh>
#include <click/task.hh>
#include <click/standard/threadsched.hh>
#if CLICK_NS
# include <click/simclick.h>
#endif
CLICK_DECLS
class Master;
class ElementFilter;
class RouterVisitor;
class RouterThread;
class HashMap_ArenaFactory;
class NotifierSignal;
class ThreadSched;
class Handler;
class NameInfo;
class Router { public:
/** @name Public Member Functions */
//@{
// MASTER
inline Master* master() const;
// STATUS
inline bool initialized() const;
inline bool handlers_ready() const;
inline bool running() const;
inline bool dying() const;
// RUNCOUNT AND RUNCLASS
enum { STOP_RUNCOUNT = -2147483647 - 1 };
inline int32_t runcount() const;
void adjust_runcount(int32_t delta);
void set_runcount(int32_t rc);
inline void please_stop_driver();
// ELEMENTS
inline const Vector<Element*>& elements() const;
inline int nelements() const;
inline Element* element(int i) const;
inline Element* root_element() const;
static Element* element(const Router *router, int i);
const String& ename(int i) const;
String ename_context(int i) const;
String elandmark(int i) const;
const String& econfiguration(int i) const;
void set_econfiguration(int i, const String& conf);
Element* find(const String& name, ErrorHandler* errh = 0) const;
Element* find(const String& name, String context, ErrorHandler* errh = 0) const;
Element* find(const String& name, const Element* context, ErrorHandler* errh = 0) const;
int visit(Element *e, bool isoutput, int port, RouterVisitor *visitor) const;
int visit_downstream(Element *e, int port, RouterVisitor *visitor) const;
int visit_upstream(Element *e, int port, RouterVisitor *visitor) const;
int downstream_elements(Element *e, int port, ElementFilter *filter, Vector<Element*> &result) CLICK_DEPRECATED;
int upstream_elements(Element *e, int port, ElementFilter *filter, Vector<Element*> &result) CLICK_DEPRECATED;
inline const char *flow_code_override(int eindex) const;
void set_flow_code_override(int eindex, const String &flow_code);
// HANDLERS
// 'const Handler *' results last until that element/handlername modified
static const Handler *handler(const Element *e, const String &hname);
static void add_read_handler(const Element *e, const String &hname, ReadHandlerCallback callback, void *user_data, uint32_t flags = 0);
static void add_write_handler(const Element *e, const String &hname, WriteHandlerCallback callback, void *user_data, uint32_t flags = 0);
static void set_handler(const Element *e, const String &hname, uint32_t flags, HandlerCallback callback, void *read_user_data = 0, void *write_user_data = 0);
static int set_handler_flags(const Element *e, const String &hname, uint32_t set_flags, uint32_t clear_flags = 0);
enum { FIRST_GLOBAL_HANDLER = 0x40000000 };
static int hindex(const Element *e, const String &hname);
static const Handler *handler(const Router *router, int hindex);
static void element_hindexes(const Element *e, Vector<int> &result);
// ATTACHMENTS AND REQUIREMENTS
void* attachment(const String& aname) const;
void*& force_attachment(const String& aname);
void* set_attachment(const String& aname, void* value);
ErrorHandler* chatter_channel(const String& channel_name) const;
HashMap_ArenaFactory* arena_factory() const;
inline ThreadSched* thread_sched() const;
inline void set_thread_sched(ThreadSched* scheduler);
inline int home_thread_id(const Element* e) const;
inline void set_home_thread_id(const Element* e, int home_thread);
/** @cond never */
// Needs to be public for NameInfo, but not useful outside
inline NameInfo* name_info() const;
NameInfo* force_name_info();
/** @endcond never */
// UNPARSING
String configuration_string() const;
void unparse(StringAccum& sa, const String& indent = String()) const;
void unparse_requirements(StringAccum& sa, const String& indent = String()) const;
void unparse_declarations(StringAccum& sa, const String& indent = String()) const;
void unparse_connections(StringAccum& sa, const String& indent = String()) const;
String element_ports_string(const Element *e) const;
//@}
// INITIALIZATION
/** @name Internal Functions */
//@{
Router(const String& configuration, Master* master);
~Router();
static void static_initialize();
static void static_cleanup();
inline void use();
void unuse();
void add_requirement(const String &type, const String &value);
int add_element(Element *e, const String &name, const String &conf, const String &filename, unsigned lineno);
int add_connection(int from_idx, int from_port, int to_idx, int to_port);
#if CLICK_LINUXMODULE
int add_module_ref(struct module* module);
#endif
inline Router* hotswap_router() const;
void set_hotswap_router(Router* router);
int initialize(ErrorHandler* errh);
void activate(bool foreground, ErrorHandler* errh);
inline void activate(ErrorHandler* errh);
inline void set_foreground(bool foreground);
int new_notifier_signal(const char *name, NotifierSignal &signal);
String notifier_signal_name(const atomic_uint32_t *signal) const;
//@}
/** @cond never */
// Needs to be public for Lexer, etc., but not useful outside
struct Port {
int idx;
int port;
Port() {
}
Port(int i, int p)
: idx(i), port(p) {
}
bool operator==(const Port &x) const {
return idx == x.idx && port == x.port;
}
bool operator!=(const Port &x) const {
return idx != x.idx || port != x.port;
}
bool operator<(const Port &x) const {
return idx < x.idx || (idx == x.idx && port < x.port);
}
bool operator<=(const Port &x) const {
return idx < x.idx || (idx == x.idx && port <= x.port);
}
};
struct Connection {
Port p[2];
Connection() {
}
Connection(int from_idx, int from_port, int to_idx, int to_port) {
p[0] = Port(to_idx, to_port);
p[1] = Port(from_idx, from_port);
}
const Port &operator[](int i) const {
assert(i >= 0 && i < 2);
return p[i];
}
Port &operator[](int i) {
assert(i >= 0 && i < 2);
return p[i];
}
bool operator==(const Connection &x) const {
return p[0] == x.p[0] && p[1] == x.p[1];
}
bool operator<(const Connection &x) const {
return p[0] < x.p[0] || (p[0] == x.p[0] && p[1] < x.p[1]);
}
};
/** @endcond never */
#if CLICK_NS
simclick_node_t *simnode() const;
int sim_get_ifid(const char* ifname);
int sim_listen(int ifid, int element);
int sim_if_ready(int ifid);
int sim_write(int ifid, int ptype, const unsigned char *, int len,
simclick_simpacketinfo *pinfo);
int sim_incoming_packet(int ifid, int ptype, const unsigned char *,
int len, simclick_simpacketinfo* pinfo);
void sim_trace(const char* event);
int sim_get_node_id();
int sim_get_next_pkt_id();
int sim_if_promisc(int ifid);
protected:
Vector<Vector<int> *> _listenvecs;
Vector<int>* sim_listenvec(int ifid);
#endif
private:
class RouterContextErrh;
enum {
ROUTER_NEW, ROUTER_PRECONFIGURE, ROUTER_PREINITIALIZE,
ROUTER_LIVE, ROUTER_DEAD // order is important
};
enum {
RUNNING_DEAD = -2, RUNNING_INACTIVE = -1, RUNNING_PREPARING = 0,
RUNNING_BACKGROUND = 1, RUNNING_ACTIVE = 2
};
Master* _master;
atomic_uint32_t _runcount;
volatile int _state;
bool _have_connections : 1;
mutable bool _conn_sorted : 1;
bool _have_configuration : 1;
volatile int _running;
atomic_uint32_t _refcount;
Vector<Element *> _elements;
Vector<String> _element_names;
Vector<String> _element_configurations;
Vector<uint32_t> _element_landmarkids;
mutable Vector<int> _element_home_thread_ids;
struct element_landmark_t {
uint32_t first_landmarkid;
String filename;
};
Vector<element_landmark_t> _element_landmarks;
uint32_t _last_landmarkid;
mutable Vector<int> _element_name_sorter;
Vector<int> _element_gport_offset[2];
Vector<int> _element_configure_order;
mutable Vector<Connection> _conn;
mutable Vector<int> _conn_output_sorter;
Vector<String> _requirements;
Vector<int> _ehandler_first_by_element;
Vector<int> _ehandler_to_handler;
Vector<int> _ehandler_next;
Vector<int> _handler_first_by_name;
enum { HANDLER_BUFSIZ = 256 };
Handler** _handler_bufs;
int _nhandlers_bufs;
int _free_handler;
Vector<String> _attachment_names;
Vector<void*> _attachments;
Element* _root_element;
String _configuration;
struct notifier_signals_t {
enum { capacity = 4096 };
String name;
int nsig;
atomic_uint32_t sig[capacity / 32];
notifier_signals_t *next;
notifier_signals_t(const String &n, notifier_signals_t *nx)
: name(n), nsig(0), next(nx) {
memset(&sig[0], 0, sizeof(sig));
}
};
notifier_signals_t *_notifier_signals;
HashMap_ArenaFactory* _arena_factory;
Router* _hotswap_router;
ThreadSched* _thread_sched;
mutable NameInfo* _name_info;
Vector<int> _flow_code_override_eindex;
Vector<String> _flow_code_override;
Router* _next_router;
#if CLICK_LINUXMODULE
Vector<struct module*> _modules;
#endif
Router(const Router&);
Router& operator=(const Router&);
Connection *remove_connection(Connection *cp);
void hookup_error(const Port &p, bool isoutput, const char *message,
ErrorHandler *errh, bool active = false);
int check_hookup_elements(ErrorHandler*);
int check_hookup_range(ErrorHandler*);
int check_hookup_completeness(ErrorHandler*);
const char *hard_flow_code_override(int e) const;
int processing_error(const Connection &conn, bool, int, ErrorHandler*);
int check_push_and_pull(ErrorHandler*);
void set_connections();
void sort_connections() const;
int connindex_lower_bound(bool isoutput, const Port &port) const;
void make_gports();
inline int ngports(bool isout) const {
return _element_gport_offset[isout].back();
}
inline int gport(bool isoutput, const Port &port) const;
int hard_home_thread_id(const Element *e) const;
int element_lerror(ErrorHandler*, Element*, const char*, ...) const;
// private handler methods
void initialize_handlers(bool, bool);
inline Handler* xhandler(int) const;
int find_ehandler(int, const String&, bool allow_star) const;
static inline Handler fetch_handler(const Element*, const String&);
void store_local_handler(int eindex, Handler &h);
static void store_global_handler(Handler &h);
static inline void store_handler(const Element *element, Handler &h);
// global handlers
static String router_read_handler(Element *e, void *user_data);
static int router_write_handler(const String &str, Element *e, void *user_data, ErrorHandler *errh);
/** @cond never */
friend class Master;
friend class Task;
friend int Element::set_nports(int, int);
/** @endcond never */
};
/** @brief Increment the router's reference count.
*
* Routers are reference counted objects. A Router is created with one
* reference, which is held by its Master object. Normally the Router and
* all its elements will be deleted when the Master drops this reference, but
* you can preserve the Router for longer by adding a reference yourself. */
inline void
Router::use()
{
_refcount++;
}
/** @brief Return true iff the router is currently running.
*
* A running router has been successfully initialized (so running() implies
* initialized()), and has not stopped yet. */
inline bool
Router::running() const
{
return _running > 0;
}
/** @brief Return true iff the router is in the process of being killed. */
inline bool
Router::dying() const
{
return _running == RUNNING_DEAD;
}
/** @brief Return true iff the router has been successfully initialized. */
inline bool
Router::initialized() const
{
return _state == ROUTER_LIVE;
}
/** @brief Return true iff the router's handlers have been initialized.
*
* handlers_ready() returns false until each element's
* Element::add_handlers() method has been called. This happens after
* Element::configure(), but before Element::initialize(). */
inline bool
Router::handlers_ready() const
{
return _state > ROUTER_PRECONFIGURE;
}
/** @brief Returns a vector containing all the router's elements.
* @invariant elements()[i] == element(i) for all i in range. */
inline const Vector<Element*>&
Router::elements() const
{
return _elements;
}
/** @brief Returns the number of elements in the router. */
inline int
Router::nelements() const
{
return _elements.size();
}
/** @brief Returns the element with index @a i.
* @param i element index, or -1 for root_element()
* @invariant If element(i) isn't null, then element(i)->@link Element::eindex eindex@endlink() == i.
*
* This function returns the element with index @a i. If @a i ==
* -1, returns root_element(). If @a i is otherwise out of range,
* returns null. */
inline Element*
Router::element(int i) const
{
return element(this, i);
}
/** @brief Returns this router's root element.
*
* Every router has a root Element. This element has Element::eindex() -1 and
* name "". It is not configured or initialized, and doesn't appear in the
* configuration; it exists only for convenience, when other Click code needs
* to refer to some arbitrary element at the top level of the compound
* element hierarchy. */
inline Element*
Router::root_element() const
{
return _root_element;
}
inline ThreadSched*
Router::thread_sched() const
{
return _thread_sched;
}
inline void
Router::set_thread_sched(ThreadSched* ts)
{
_thread_sched = ts;
}
inline int
Router::home_thread_id(const Element* e) const
{
if (initialized())
return _element_home_thread_ids[e->eindex() + 1];
else
return hard_home_thread_id(e);
}
inline void
Router::set_home_thread_id(const Element* e, int home_thread_id)
{
_element_home_thread_ids[e->eindex() + 1] = home_thread_id;
}
/** @cond never */
/** @brief Return the NameInfo object for this router, if it exists.
*
* Users never need to call this. */
inline NameInfo*
Router::name_info() const
{
return _name_info;
}
/** @endcond never */
/** @brief Return the Master object for this router. */
inline Master*
Router::master() const
{
return _master;
}
/** @brief Return the router's runcount.
*
* The runcount is an integer that determines whether the router is running.
* A running router has positive runcount. Decrementing the router's runcount
* to zero or below will cause the router to stop, although elements like
* DriverManager can intercept the stop request and continue processing.
*
* Elements request that the router stop its processing by calling
* adjust_runcount() or please_stop_driver(). */
inline int32_t
Router::runcount() const
{
return _runcount.value();
}
/** @brief Request a driver stop by adjusting the runcount by -1.
* @note Equivalent to adjust_runcount(-1). */
inline void
Router::please_stop_driver()
{
adjust_runcount(-1);
}
/** @brief Returns the overriding flow code for element @a e, if any.
* @param eindex element index
* @return The flow code, or null if none has been set. */
inline const char *
Router::flow_code_override(int eindex) const
{
if (_flow_code_override.size())
return hard_flow_code_override(eindex);
else
return 0;
}
inline void
Router::activate(ErrorHandler* errh)
{
activate(true, errh);
}
inline void
Router::set_foreground(bool foreground)
{
assert(_running >= RUNNING_BACKGROUND);
_running = foreground ? RUNNING_ACTIVE : RUNNING_BACKGROUND;
}
/** @brief Finds an element named @a name.
* @param name element name
* @param errh optional error handler
*
* Returns the unique element named @a name, if any. If no element named @a
* name is found, reports an error to @a errh and returns null. The error is
* "<tt>no element named 'name'</tt>". If @a errh is null, no error is
* reported.
*
* This function is equivalent to find(const String&, String, ErrorHandler*)
* with a context argument of the empty string. */
inline Element *
Router::find(const String& name, ErrorHandler *errh) const
{
return find(name, "", errh);
}
/** @brief Traverse the router configuration downstream of @a e[@a port].
* @param e element to start search
* @param port output port (or -1 to search all output ports)
* @param visitor RouterVisitor traversal object
* @return 0 on success, -1 in early router configuration stages
*
* Calls @a visitor ->@link RouterVisitor::visit visit() @endlink on each
* reachable input port starting from the output port @a e[@a port]. Follows
* connections and traverses inside elements from port to port by
* Element::flow_code(). The visitor can stop a traversal path by returning
* false from visit().
*
* @sa visit_upstream(), visit()
*/
inline int
Router::visit_downstream(Element *e, int port, RouterVisitor *visitor) const
{
return visit(e, true, port, visitor);
}
/** @brief Traverse the router configuration upstream of [@a port]@a e.
* @param e element to start search
* @param port input port (or -1 to search all input ports)
* @param visitor RouterVisitor traversal object
* @return 0 on success, -1 in early router configuration stages
*
* Calls @a visitor ->@link RouterVisitor::visit visit() @endlink on each
* reachable output port starting from the input port [@a port]@a e. Follows
* connections and traverses inside elements from port to port by
* Element::flow_code(). The visitor can stop a traversal path by returning
* false from visit().
*
* @sa visit_downstream(), visit()
*/
inline int
Router::visit_upstream(Element *e, int port, RouterVisitor *visitor) const
{
return visit(e, false, port, visitor);
}
inline HashMap_ArenaFactory*
Router::arena_factory() const
{
return _arena_factory;
}
/** @brief Returns the currently-installed router this router will eventually
* replace.
*
* This function is only meaningful during a router's initialization. If this
* router was installed with the hotswap option, then hotswap_router() will
* return the currently-installed router that this router will eventually
* replace (assuming error-free initialization). Otherwise, hotswap_router()
* will return 0.
*/
inline Router*
Router::hotswap_router() const
{
return _hotswap_router;
}
inline
Handler::Handler(const String &name)
: _name(name), _read_user_data(0), _write_user_data(0), _flags(0),
_use_count(0), _next_by_name(-1)
{
_read_hook.r = 0;
_write_hook.w = 0;
}
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,527 @@
// -*- c-basic-offset: 4; related-file-name: "../../lib/routerthread.cc" -*-
#ifndef CLICK_ROUTERTHREAD_HH
#define CLICK_ROUTERTHREAD_HH
#include <click/sync.hh>
#include <click/vector.hh>
#include <click/timerset.hh>
#if CLICK_LINUXMODULE
# include <click/cxxprotect.h>
CLICK_CXX_PROTECT
# include <linux/sched.h>
CLICK_CXX_UNPROTECT
# include <click/cxxunprotect.h>
#elif CLICK_BSDMODULE
# include <click/cxxprotect.h>
CLICK_CXX_PROTECT
# include <sys/systm.h>
CLICK_CXX_UNPROTECT
# include <click/cxxunprotect.h>
#elif CLICK_USERLEVEL
# include <click/selectset.hh>
#endif
// NB: user must #include <click/task.hh> before <click/routerthread.hh>.
// We cannot #include <click/task.hh> ourselves because of circular #include
// dependency.
CLICK_DECLS
class RouterThread { public:
enum { THREAD_QUIESCENT = -1, THREAD_UNKNOWN = -1000 };
inline int thread_id() const;
inline Master *master() const;
inline TimerSet &timer_set() { return _timers; }
inline const TimerSet &timer_set() const { return _timers; }
#if CLICK_USERLEVEL
inline SelectSet &select_set() { return _selects; }
inline const SelectSet &select_set() const { return _selects; }
#endif
// Task list functions
inline bool active() const;
inline Task *task_begin() const;
inline Task *task_next(Task *task) const;
inline Task *task_end() const;
void scheduled_tasks(Router *router, Vector<Task *> &x);
inline void lock_tasks();
inline void unlock_tasks();
inline void schedule_block_tasks();
inline void block_tasks(bool scheduled);
inline void unblock_tasks();
inline bool stop_flag() const;
inline void mark_driver_entry();
void driver();
void kill_router(Router *router);
#if HAVE_ADAPTIVE_SCHEDULER
// min_cpu_share() and max_cpu_share() are expressed on a scale with
// Task::MAX_UTILIZATION == 100%.
unsigned min_cpu_share() const { return _min_click_share; }
unsigned max_cpu_share() const { return _max_click_share; }
unsigned cur_cpu_share() const { return _cur_click_share; }
void set_cpu_share(unsigned min_share, unsigned max_share);
#endif
#if CLICK_LINUXMODULE || CLICK_BSDMODULE
bool greedy() const { return _greedy; }
void set_greedy(bool g) { _greedy = g; }
#endif
inline void wake();
#if CLICK_USERLEVEL
inline void run_signals();
#endif
enum { S_PAUSED, S_BLOCKED, S_TIMERWAIT,
S_LOCKSELECT, S_LOCKTASKS,
S_RUNTASK, S_RUNTIMER, S_RUNSIGNAL, S_RUNPENDING, S_RUNSELECT,
NSTATES };
inline void set_thread_state(int state);
inline void set_thread_state_for_blocking(int delay_type);
#if CLICK_DEBUG_SCHEDULING
int thread_state() const { return _thread_state; }
static String thread_state_name(int state);
uint32_t driver_epoch() const { return _driver_epoch; }
uint32_t driver_task_epoch() const { return _driver_task_epoch; }
Timestamp task_epoch_time(uint32_t epoch) const;
# if CLICK_LINUXMODULE
struct task_struct *sleeper() const { return _linux_task; }
# endif
# if CLICK_DEBUG_SCHEDULING > 1
inline Timestamp thread_state_time(int state) const;
inline uint64_t thread_state_count(int state) const;
# endif
#endif
private:
#if HAVE_TASK_HEAP
struct task_heap_element {
unsigned pass;
Task *t;
task_heap_element() {
}
task_heap_element(Task *t_)
: pass(t_->_pass), t(t_) {
}
};
#endif
// LOCAL STATE GROUP
TaskLink _task_link;
volatile bool _stop_flag;
#if HAVE_TASK_HEAP
Vector<task_heap_element> _task_heap;
#endif
TimerSet _timers;
#if CLICK_USERLEVEL
SelectSet _selects;
#endif
#if HAVE_ADAPTIVE_SCHEDULER
enum { C_CLICK, C_KERNEL, NCLIENTS };
struct Client { // top-level stride clients
unsigned pass;
unsigned stride;
int tickets;
Client() : pass(0), tickets(0) { }
};
Client _clients[NCLIENTS];
unsigned _global_pass; // global pass
unsigned _max_click_share; // maximum allowed Click share of CPU
unsigned _min_click_share; // minimum allowed Click share of CPU
unsigned _cur_click_share; // current Click share
Timestamp _adaptive_restride_timestamp;
int _adaptive_restride_iter;
#endif
// EXTERNAL STATE GROUP
Spinlock _task_lock CLICK_ALIGNED(CLICK_CACHE_LINE_SIZE);
atomic_uint32_t _task_blocker;
atomic_uint32_t _task_blocker_waiting;
Task::Pending _pending_head;
Task::Pending *_pending_tail;
SpinlockIRQ _pending_lock;
// SHARED STATE GROUP
Master *_master CLICK_ALIGNED(CLICK_CACHE_LINE_SIZE);
int _id;
bool _driver_entered;
#if HAVE_MULTITHREAD && !(CLICK_LINUXMODULE || CLICK_MINIOS)
click_processor_t _running_processor;
#endif
#if CLICK_LINUXMODULE
bool _greedy;
struct task_struct *_linux_task;
#endif
#if CLICK_MINIOS
struct thread *_minios_thread;
#endif
public:
unsigned _tasks_per_iter;
unsigned _iters_per_os;
private:
#if CLICK_NS
Timestamp _ns_scheduled;
Timestamp _ns_last_active;
int _ns_active_iter;
enum { ns_iters_per_time = 1000 };
#endif
#if CLICK_BSDMODULE
// XXX FreeBSD
u_int64_t _old_tsc; /* MARKO - temp. */
void *_sleep_ident;
int _oticks;
bool _greedy;
#endif
#if CLICK_DEBUG_SCHEDULING
int _thread_state;
uint32_t _driver_epoch;
uint32_t _driver_task_epoch;
enum { TASK_EPOCH_BUFSIZ = 32 };
uint32_t _task_epoch_first;
Timestamp _task_epoch_time[TASK_EPOCH_BUFSIZ];
# if CLICK_DEBUG_SCHEDULING > 1
Timestamp _thread_state_time[NSTATES];
uint64_t _thread_state_count[NSTATES];
Timestamp _thread_state_timestamp;
# endif
#endif
// called by Master
RouterThread(Master *master, int threadno);
~RouterThread();
// task requests
inline void add_pending();
#if HAVE_STRIDE_SCHED
inline unsigned pass() const {
# if HAVE_TASK_HEAP
return _task_heap.size() ? _task_heap.unchecked_at(0).pass : 0;
# else
return _task_link._next->_pass;
# endif
}
#endif
// task running functions
void driver_lock_tasks();
inline void driver_unlock_tasks() {
uint32_t val = _task_blocker.compare_swap((uint32_t) -1, 0);
(void) val;
assert(val == (uint32_t) -1);
}
inline void run_tasks(int ntasks);
inline void process_pending();
inline void run_os();
#if HAVE_ADAPTIVE_SCHEDULER
void client_set_tickets(int client, int tickets);
inline void client_update_pass(int client, const Timestamp &before);
#endif
#if HAVE_TASK_HEAP
void task_reheapify_from(int pos, Task*);
#endif
static inline bool running_in_interrupt();
inline bool current_thread_is_running() const;
inline bool current_thread_is_running_cleanup() const;
friend class Task;
friend class Master;
#if CLICK_USERLEVEL
friend class SelectSet;
#endif
};
/** @brief Returns this thread's ID.
*
* The result is >= 0 for true threads, and < 0 for threads that never run any
* of their associated Tasks.
*/
inline int
RouterThread::thread_id() const
{
return _id;
}
/** @brief Returns this thread's associated Master. */
inline Master*
RouterThread::master() const
{
return _master;
}
/** @brief Returns whether any tasks are scheduled.
*
* Returns false iff no tasks are scheduled and no events are pending. Since
* not all events actually matter (for example, a Task might have been
* scheduled and then subsequently unscheduled), active() may temporarily
* return true even when no real events are outstanding.
*/
inline bool
RouterThread::active() const
{
click_compiler_fence();
#if HAVE_TASK_HEAP
return _task_heap.size() != 0 || _pending_head.x;
#else
return _task_link._next != &_task_link || _pending_head.x;
#endif
}
/** @brief Returns the beginning of the scheduled task list.
*
* Each RouterThread maintains a list of all currently-scheduled tasks.
* Elements may traverse this list with the task_begin(), task_next(), and
* task_end() functions, using iterator-like code such as:
*
* @code
* thread->lock_tasks();
* for (Task *t = thread->task_begin();
* t != thread->task_end();
* t = thread->task_next(t)) {
* // ... do something with t...
* }
* thread->unlock_tasks();
* @endcode
*
* The thread's task lock must be held during the traversal, as shown above.
*
* The return value may not be a real task. Test it against task_end() before
* use.
*
* @sa task_next, task_end, lock_tasks, unlock_tasks
*/
inline Task *
RouterThread::task_begin() const
{
#if HAVE_TASK_HEAP
return (_task_heap.size() ? _task_heap.unchecked_at(0).t : 0);
#else
return static_cast<Task *>(_task_link._next);
#endif
}
/** @brief Returns the task following @a task in the scheduled task list.
* @param task the current task
*
* The return value may not be a real task. Test it against task_end() before
* use. However, the @a task argument must be a real task; do not attempt to
* call task_next(task_end()).
*
* @sa task_begin for usage, task_end
*/
inline Task *
RouterThread::task_next(Task *task) const
{
#if HAVE_TASK_HEAP
int p = task->_schedpos + 1;
return (p < _task_heap.size() ? _task_heap.unchecked_at(p).t : 0);
#else
return static_cast<Task *>(task->_next);
#endif
}
/** @brief Returns the end of the scheduled task list.
*
* The return value is not a real task.
*
* @sa task_begin for usage, task_next
*/
inline Task *
RouterThread::task_end() const
{
#if HAVE_TASK_HEAP
return 0;
#else
return static_cast<Task *>(const_cast<TaskLink *>(&_task_link));
#endif
}
inline bool
RouterThread::running_in_interrupt()
{
#if CLICK_LINUXMODULE
return in_interrupt();
#else
return false;
#endif
}
inline void
RouterThread::mark_driver_entry()
{
_driver_entered = true;
}
inline bool
RouterThread::current_thread_is_running() const
{
#if CLICK_LINUXMODULE
return current == _linux_task && !running_in_interrupt();
#elif CLICK_MINIOS
return get_current() == _minios_thread;
#elif CLICK_USERLEVEL && HAVE_MULTITHREAD && HAVE___THREAD_STORAGE_CLASS
return click_current_thread_id == (_id | 0x40000000);
#elif CLICK_USERLEVEL && HAVE_MULTITHREAD
return click_current_processor() == _running_processor;
#else
return true;
#endif
}
inline bool
RouterThread::current_thread_is_running_cleanup() const
{
return current_thread_is_running() || (!_driver_entered && _id >= 0);
}
inline void
RouterThread::schedule_block_tasks()
{
assert(!current_thread_is_running());
++_task_blocker_waiting;
}
inline void
RouterThread::block_tasks(bool scheduled)
{
assert(!current_thread_is_running() && !running_in_interrupt());
if (!scheduled)
++_task_blocker_waiting;
while (1) {
uint32_t blocker = _task_blocker.value();
if ((int32_t) blocker >= 0
&& _task_blocker.compare_swap(blocker, blocker + 1) == blocker)
break;
#if CLICK_LINUXMODULE
// 3.Nov.2008: Must allow other threads a chance to run. Otherwise,
// soft lock is possible: the thread in block_tasks() waits for
// RouterThread::_linux_task to complete a task set, but
// RouterThread::_linux_task can't run until the thread in
// block_tasks() relinquishes the CPU.
//
// We might be able to avoid schedule() in some cases, but don't
// bother to try.
schedule();
#endif
}
--_task_blocker_waiting;
}
inline void
RouterThread::unblock_tasks()
{
assert((int32_t) _task_blocker.value() > 0);
--_task_blocker;
}
inline void
RouterThread::lock_tasks()
{
assert(!running_in_interrupt());
if (unlikely(!current_thread_is_running())) {
block_tasks(false);
_task_lock.acquire();
}
}
inline void
RouterThread::unlock_tasks()
{
assert(!running_in_interrupt());
if (unlikely(!current_thread_is_running())) {
_task_lock.release();
unblock_tasks();
}
}
inline void
RouterThread::wake()
{
#if CLICK_LINUXMODULE
struct task_struct *task = _linux_task;
if (task)
wake_up_process(task);
#elif CLICK_USERLEVEL
// see also Master::add_select()
if (!current_thread_is_running())
_selects.wake_immediate();
#elif CLICK_BSDMODULE && !BSD_NETISRSCHED
if (_sleep_ident)
wakeup_one(&_sleep_ident);
#endif
}
inline void
RouterThread::add_pending()
{
wake();
}
inline bool
RouterThread::stop_flag() const
{
return _stop_flag;
}
inline void
RouterThread::set_thread_state(int state)
{
(void) state;
#if CLICK_DEBUG_SCHEDULING
assert(state >= 0 && state < NSTATES);
# if CLICK_DEBUG_SCHEDULING > 1
Timestamp now = Timestamp::now();
if (_thread_state_timestamp)
_thread_state_time[_thread_state] += now - _thread_state_timestamp;
if (_thread_state != state)
++_thread_state_count[_thread_state];
_thread_state_timestamp = now;
# endif
_thread_state = state;
#endif
}
inline void
RouterThread::set_thread_state_for_blocking(int delay_type)
{
if (delay_type < 0)
set_thread_state(S_BLOCKED);
else
set_thread_state(delay_type ? S_TIMERWAIT : S_PAUSED);
}
#if CLICK_DEBUG_SCHEDULING > 1
inline Timestamp
RouterThread::thread_state_time(int state) const
{
assert(state >= 0 && state < NSTATES);
return _thread_state_time[state];
}
inline uint64_t
RouterThread::thread_state_count(int state) const
{
assert(state >= 0 && state < NSTATES);
return _thread_state_count[state];
}
#endif
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,193 @@
// -*- c-basic-offset: 4; related-file-name: "../../lib/routervisitor.cc" -*-
#ifndef CLICK_ROUTERVISITOR_HH
#define CLICK_ROUTERVISITOR_HH
#include <click/element.hh>
#include <click/bitvector.hh>
CLICK_DECLS
/** @class RouterVisitor
* @brief Base class for router configuration visitors.
*
* RouterVisitor objects are used to traverse the router configuration graph.
* They are usually passed to the Router::visit_downstream() and
* Router::visit_upstream() functions.
*/
class RouterVisitor { public:
/** @brief Construct an RouterVisitor. */
RouterVisitor() {
}
/** @brief Destroy an RouterVisitor. */
virtual ~RouterVisitor() {
}
/** @brief Visit an element.
* @param e element being visited
* @param isoutput true for output ports, false for input ports
* @param port port number being visited
* @param from_e element by which @a e was reached
* @param from_port port by which @a e/@a port was reached
* @param distance connection distance in breadth-first search
* @return true to continue traversing, false to stop
*
* A Router configuration traversal calls this function once on each
* reached port. Configuration traversal is breadth-first; @a distance is
* the minimum connection distance from the traversal's start point to @a
* e/@a port. A traversal will call a port's visit() function at most
* once. @a from_e and @a from_port specify one port that is connected to
* @a e and @a port (there may be more than one). If @a isoutput is true,
* then @a e/@a port is an output port and @a from_e/@a from_port is an
* input port; if @a isoutput is false, the opposite holds.
*
* The return value specifies whether traversal should continue through
* the @a e element. If it is true, then the traversal will continue
* based on @a e's packet flow specifier, via ports that connect to @a
* e/@a port (see Element::flow_code() for more).
*
* The default implementation always returns true.
*/
virtual bool visit(Element *e, bool isoutput, int port,
Element *from_e, int from_port, int distance);
};
/** @class ElementTracker
* @brief Base class for router configuration visitors that collect elements.
*
* ElementTracker is a type of RouterVisitor used to traverse the router
* configuration graph and collect matching elements. A subclass's @link
* RouterVisitor::visit visit() @endlink function will call insert() to store
* elements that match. ElementTracker objects are usually passed to the
* Router::visit_downstream() and Router::visit_upstream() functions.
*/
class ElementTracker : public RouterVisitor { public:
/** @brief Construct an ElementTracker.
* @param router the router to be traversed */
ElementTracker(Router *router);
/** @brief Return the elements that matched. */
const Vector<Element *> &elements() const {
return _elements;
}
/** @brief Return the number of matching elements. */
int size() const {
return _elements.size();
}
/** @brief Return the @a i'th matching element.
*
* Elements are ordered by their time of first insertion. */
Element *operator[](int i) const {
return _elements[i];
}
/** @brief Iterator type. */
typedef Vector<Element *>::const_iterator const_iterator;
/** @brief Return an iterator for the first matching element. */
const_iterator begin() const {
return _elements.begin();
}
/** @brief Return an iterator for the end of the container. */
const_iterator end() const {
return _elements.end();
}
/** @brief Return true iff element @a e is a matching element. */
bool contains(const Element *e) const {
return _reached[e->eindex()];
}
/** @brief Add element @a e to the set of matching elements. */
void insert(Element *e) {
if (!_reached[e->eindex()]) {
_reached[e->eindex()] = true;
_elements.push_back(e);
}
}
/** @brief Clear the set of matching elements. */
void clear() {
_reached.clear();
_elements.clear();
}
private:
Bitvector _reached;
Vector<Element *> _elements;
};
/** @class ElementCastTracker
* @brief Router configuration visitor that collects elements that match a
* certain cast.
*
* When passed to Router::visit_upstream() or Router::visit_downstream(),
* ElementCastTracker collects the closest elements that successfully cast to
* @a name. For instance, this code will find the closest Storage elements
* upstream of [0]@a e:
* @code
* ElementCastTracker tracker(e->router(), "Storage");
* e->router()->visit_upstream(e, 0, &tracker);
* tracker.elements(); // a Vector<Element *> containing the Storage elements
* @endcode
*
* Graph traversal stops at each matching element, so in the above example, a
* Storage element that is "behind" another Storage element won't be returned.
*/
class ElementCastTracker : public ElementTracker { public:
/** @brief Construct an ElementCastTracker.
* @param router the router to be traversed
* @param name the cast of interest */
ElementCastTracker(Router *router, const String &name)
: ElementTracker(router), _name(name) {
}
bool visit(Element *e, bool isoutput, int port,
Element *from_e, int from_port, int distance);
private:
String _name;
};
/** @class ElementNeighborhoodTracker
* @brief Router configuration visitor that collects close-by elements.
*
* When passed to Router::visit_upstream() or Router::visit_downstream(),
* ElementNeighborhoodTracker collects the elements that are within a certain
* number of connections of the source element. For instance, this code will
* find all the elements connected to [0]@a e:
* @code
* ElementNeighborhoodTracker tracker(e->router());
* e->router()->visit_upstream(e, 0, &tracker);
* tracker.elements(); // Vector<Element *> containing neighboring elements
* @endcode
*
* Supply the constructor's @a diameter argument to find a larger neighborhood
* than just the directly-connected elements.
*/
class ElementNeighborhoodTracker : public ElementTracker { public:
/** @brief Construct an ElementNeighborhoodTracker.
* @param router the router to be traversed
* @param diameter neighborhood diameter (maximum number of connections to
* traverse) */
ElementNeighborhoodTracker(Router *router, int diameter = 1)
: ElementTracker(router), _diameter(diameter) {
}
bool visit(Element *e, bool isoutput, int port,
Element *from_e, int from_port, int distance);
private:
int _diameter;
};
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,137 @@
// -*- related-file-name: "../../lib/selectset.cc" -*-
#ifndef CLICK_SELECTSET_HH
#define CLICK_SELECTSET_HH 1
#if !CLICK_USERLEVEL
# error "<click/selectset.hh> only meaningful at user level"
#endif
#include <click/vector.hh>
#include <click/sync.hh>
#include <unistd.h>
#if !HAVE_ALLOW_SELECT && !HAVE_ALLOW_POLL && !HAVE_ALLOW_KQUEUE
# define HAVE_ALLOW_SELECT 1
#endif
#if defined(__APPLE__) && HAVE_ALLOW_SELECT && HAVE_ALLOW_POLL
// Apple's poll() is often broken
# undef HAVE_ALLOW_POLL
#endif
#if HAVE_POLL_H && HAVE_ALLOW_POLL
# include <poll.h>
#else
# undef HAVE_ALLOW_POLL
# if !HAVE_ALLOW_SELECT && !HAVE_ALLOW_KQUEUE
# error "poll is not supported on this system, try --enable-select"
# endif
#endif
#if !HAVE_SYS_EVENT_H || !HAVE_KQUEUE
# undef HAVE_ALLOW_KQUEUE
# if !HAVE_ALLOW_SELECT && !HAVE_ALLOW_POLL
# error "kqueue is not supported on this system, try --enable-select"
# endif
#endif
CLICK_DECLS
class Element;
class Router;
class RouterThread;
class SelectSet { public:
SelectSet();
~SelectSet();
void initialize();
int add_select(int fd, Element *element, int mask);
int remove_select(int fd, Element *element, int mask);
void run_selects(RouterThread *thread);
inline void wake_immediate() {
_wake_pipe_pending = true;
ignore_result(write(_wake_pipe[1], "", 1));
}
void kill_router(Router *router);
inline void fence();
private:
struct SelectorInfo {
Element *read;
Element *write;
int pollfd;
SelectorInfo()
: read(0), write(0), pollfd(-1)
{
}
};
int _wake_pipe[2];
volatile bool _wake_pipe_pending;
#if HAVE_ALLOW_KQUEUE
int _kqueue;
#endif
#if !HAVE_ALLOW_POLL
struct pollfd {
int fd;
int events;
};
fd_set _read_select_fd_set;
fd_set _write_select_fd_set;
int _max_select_fd;
#endif /* !HAVE_ALLOW_POLL */
Vector<struct pollfd> _pollfds;
Vector<SelectorInfo> _selinfo;
#if HAVE_MULTITHREAD
SimpleSpinlock _select_lock;
click_processor_t _select_processor;
#endif
void register_select(int fd, bool add_read, bool add_write);
void remove_pollfd(int pi, int event);
inline void call_selected(int fd, int mask) const;
inline bool post_select(RouterThread *thread, bool acquire);
#if HAVE_ALLOW_KQUEUE
void run_selects_kqueue(RouterThread *thread);
#endif
#if HAVE_ALLOW_POLL
void run_selects_poll(RouterThread *thread);
#else
void run_selects_select(RouterThread *thread);
#endif
inline void lock();
inline void unlock();
#if CLICK_DEBUG_MASTER || CLICK_DEBUG_SCHEDULING
friend class Master;
#endif
};
inline void
SelectSet::lock()
{
#if HAVE_MULTITHREAD
if (click_get_processor() != _select_processor)
_select_lock.acquire();
#endif
}
inline void
SelectSet::unlock()
{
#if HAVE_MULTITHREAD
if (click_get_processor() != _select_processor)
_select_lock.release();
#endif
}
inline void
SelectSet::fence()
{
lock();
unlock();
}
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,118 @@
#ifndef SIMCLICK_H
#define SIMCLICK_H
/*
* simclick.h
*
* API for sending packets to Click. Mostly intended for use
* by a network simulator which wants to use Click to do routing.
*
*/
#ifdef __cplusplus
extern "C" {
#endif
/*
* Packet types used - generally going to be ethernet, but could
* possibly be something else I suppose...
*/
#define SIMCLICK_PTYPE_UNKNOWN 0
#define SIMCLICK_PTYPE_ETHER 1
#define SIMCLICK_PTYPE_IP 2
/*
* Not a whole lot to this. We have to create a click router object
* and also send packets and trigger events.
*/
/*
* This contains per packet data we need to preserve when the packet gets
* dragged through click. Heavily biased towards ns-2 right now.
*/
typedef struct {
int id; /* Simulator ID number for the packet */
int fid; /* Simulator flow ID number for the packet */
int simtype; /* Original simulator packet type - useful
* for morphing between raw and simulator
* packet types */
} simclick_simpacketinfo;
/*
* Opaque handles for the sim and click instances
*/
typedef struct simclick_node {
void *clickinfo;
struct timeval curtime;
} simclick_node_t;
int simclick_click_create(simclick_node_t *sim, const char *router_file);
int simclick_click_send(simclick_node_t *sim,
int ifid,int type,const unsigned char* data,int len,
simclick_simpacketinfo* pinfo);
int simclick_sim_send(simclick_node_t *sim,
int ifid,int type, const unsigned char* data,int len,
simclick_simpacketinfo*);
void simclick_click_run(simclick_node_t *sim);
void simclick_click_kill(simclick_node_t *sim);
/*
* simclick_click_read_handler will allocate a buffer of adequate length
* to receive the handler information. This buffer must be freed
* by the caller. If a non-null value for the "memalloc" parameter
* is passed in, simclick_click_read_handler will use that function
* to allocate the memory. If there's a null value there, "malloc" will
* be used by default. The "memparam" parameter is a caller-specified
* value which will be passed back to the memory allocation function.
*/
typedef void* (*SIMCLICK_MEM_ALLOC)(size_t,void*);
char* simclick_click_read_handler(simclick_node_t *sim,
const char* elementname,
const char* handlername,
SIMCLICK_MEM_ALLOC memalloc,
void* memparam);
int simclick_click_write_handler(simclick_node_t *sim,
const char* elemname, const char* handlername,
const char* writestring);
/*
* We also provide a gettimeofday substitute which utilizes the
* state info passed to us by the simulator.
*/
int simclick_gettimeofday(struct timeval* tv);
/*
* The simulated system also has to provide a few services to click,
* notably some way of injecting packets back into the system,
* mapping interface names to id numbers, and arranging for click
* to execute at a specified time in the future.
* We implement
*/
#define SIMCLICK_VERSION 0 // none
#define SIMCLICK_SUPPORTS 1 // int call
#define SIMCLICK_IFID_FROM_NAME 2 // const char *ifname
#define SIMCLICK_IPADDR_FROM_NAME 3 // const char *ifname, char *buf, int len
#define SIMCLICK_MACADDR_FROM_NAME 4 // const char *ifname, char *buf, int len
#define SIMCLICK_SCHEDULE 5 // struct timeval *when
#define SIMCLICK_GET_NODE_NAME 6 // char *buf, int len
#define SIMCLICK_IF_READY 7 // int ifid
#define SIMCLICK_TRACE 8 // const char *event
#define SIMCLICK_GET_NODE_ID 9 // none
#define SIMCLICK_GET_NEXT_PKT_ID 10 // none
#define SIMCLICK_CHANGE_CHANNEL 11 // int ifid, int channelid
#define SIMCLICK_IF_PROMISC 12 // int ifid
#define SIMCLICK_IPPREFIX_FROM_NAME 13 // const char *ifname, char *buf, int len
#define SIMCLICK_GET_RANDOM_INT 14 // uint32_t *result, uint32_t max
#define SIMCLICK_GET_DEFINES 15 // char *buf, size_t *size
int simclick_sim_command(simclick_node_t *sim, int cmd, ...);
int simclick_click_command(simclick_node_t *sim, int cmd, ...);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,16 @@
// -*- c-basic-offset: 2; related-file-name: "../../linuxmodule/skbmgr.cc" -*-
#ifndef CLICK_SKBMGR_HH
#define CLICK_SKBMGR_HH
CLICK_DECLS
void skbmgr_init();
void skbmgr_cleanup();
/* allocate skbs. Number of skbs allocated is stored in the want variable */
struct sk_buff *skbmgr_allocate_skbs(unsigned headroom, unsigned size, int *want);
/* recycle skb back into pool */
void skbmgr_recycle_skbs(struct sk_buff *);
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,135 @@
// -*- related-file-name: "../../../elements/standard/addressinfo.cc" -*-
#ifndef CLICK_ADDRESSINFO_HH
#define CLICK_ADDRESSINFO_HH
#include <click/element.hh>
CLICK_DECLS
/*
=c
AddressInfo(NAME ADDRESS [ADDRESS...], ...)
=s information
specifies address information
=io
None
=d
Lets you use mnemonic names for IPv4 and IPv6 addresses, IPv4 and IPv6
address prefixes, and Ethernet addresses. Each argument has the form `NAME
ADDRESS [ADDRESS...]', which associates the given ADDRESSes with NAME. For
example, if a configuration contains this AddressInfo element,
AddressInfo(mauer 10.0.0.1, mazu 10.0.0.10);
then other configuration strings can use C<mauer> and C<mazu> as mnemonics
for the IP addresses 10.0.0.1 and 10.0.0.10, respectively.
The mnemonic names introduced by AddressInfo elements are local with
respect to compound elements. That is, names created inside a compound
element apply only within that compound element and its subelements. For
example:
AddressInfo(mauer 10.0.0.1);
compound :: {
AddressInfo(mazu 10.0.0.10);
... -> IPEncap(6, mauer, mazu) -> ... // OK
};
... -> IPEncap(6, mauer, mazu) -> ... // error: `mazu' undefined
Any name can be simultaneously associated with an IP address, an IP network
address, and an Ethernet address. The kind of address that is returned is
generally determined from context. For example:
AddressInfo(mauer 10.0.0.1 00-50-BA-85-84-A9);
... -> IPEncap(6, mauer, ...) // as IP address
-> EtherEncap(0x0800, mauer, ...) -> ... // as Ethernet address
... -> ARPResponder(mauer) -> ... // as IP address and Ethernet address!
An optional suffix makes the context unambiguous. C<NAME> is an ambiguous
reference to some address, but C<NAME:ip> is always an IPv4 address,
C<NAME:ipnet> is always an IPv4 network address (IPv4 address prefix),
C<NAME:ip6> is always an IPv6 address, C<NAME:ip6net> is always an IPv6
network address, and C<NAME:eth> is always an Ethernet address.
Names with both address and prefix definitions are preferentially parsed as
addresses. For example:
AddressInfo(boojum 10.0.0.1/24); // defines address and prefix
a1 :: ARPResponder(boojum 00-01-02-03-04-05);
// a1 will have the same configuration as:
a2 :: ARPResponder(10.0.0.1/32 00-01-02-03-04-05);
To prefer the network prefix, use C<NAME:ipnet>.
If C<NAME:ipnet> is a valid IPv4 network address, then C<NAME:bcast> is a
valid IPv4 address equaling the broadcast address for that network. This is
obtained by setting all the host bits in the address prefix to 1.
C<NAME:gw> usually equals the default gateway address for network
C<NAME>. If C<NAME> is a device, then C<NAME:gw> can sometimes be
looked up explicitly; otherwise, C<NAME:gw> is calculated from
C<NAME:ipnet> by setting the lowest-order bit in the network address.
=head1 DEFAULT ADDRESSES
If you do not define an address for a given NAME, AddressInfo will use the
default, if any. Defaults are as follows:
=over 2
=item *
For Ethernet addresses, Click checks for an Ethernet device named NAME, and
uses its address. (At userlevel, this works only on BSD and Linux.)
=item *
For IPv4 addresses, Click checks for a network device named NAME, and uses
its primary IPv4 address.
=item *
For C<NAME:gw>, Click checks for a network device named NAME, and uses its
default gateway.
=back
These defaults are not available on all platforms.
=a
PortInfo */
class AddressInfo : public Element { public:
AddressInfo();
const char *class_name() const { return "AddressInfo"; }
int configure_phase() const { return CONFIGURE_PHASE_FIRST; }
int configure(Vector<String> &conf, ErrorHandler *errh);
enum {
f_nodevice = 1
};
static bool query_ip(const String &s, unsigned char *store, const Element *context, int flags = 0);
static bool query_ip_prefix(String s, unsigned char *store_addr, unsigned char *store_mask, const Element *context, int flags = 0);
#if HAVE_IP6
static bool query_ip6(String s, unsigned char *store, const Element *context, int flags = 0);
static bool query_ip6_prefix(String s, unsigned char *store_addr, int *store_prefixlen, const Element *context, int flags = 0);
#endif
static bool query_ethernet(String s, unsigned char *store, const Element *context, int flags = 0);
private:
static bool query_netdevice(const String &name, unsigned char *store, int type, int len, const Element *context, int flags);
};
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,48 @@
// -*- related-file-name: "../../../elements/standard/alignmentinfo.cc" -*-
#ifndef CLICK_ALIGNMENTINFO_HH
#define CLICK_ALIGNMENTINFO_HH
#include <click/element.hh>
CLICK_DECLS
/*
* =c
* AlignmentInfo(ELEMENT [MODULUS OFFSET ...], ...)
* =s information
* specifies alignment information
* =io
* None
* =d
* Provides information about the packet alignment specified elements can
* expect. Each configuration argument has the form
* `ELEMENT [MODULUS0 OFFSET0 MODULUS1 OFFSET1 ...]',
* where there are zero or more MODULUS-OFFSET pairs.
* All packets arriving at ELEMENT's
* I<n>th input will start `OFFSETI<n>' bytes
* off from a `MODULUSI<n>'-byte boundary.
* =n
* This element is inserted automatically by click-align(1).
* =a Align, click-align(1)
*/
class AlignmentInfo : public Element { public:
AlignmentInfo();
const char *class_name() const { return "AlignmentInfo"; }
int configure_phase() const { return CONFIGURE_PHASE_INFO; }
int configure(Vector<String> &, ErrorHandler *);
bool query1(const Element *e, int port, int &chunk, int &offset) const;
static bool query(const Element *e, int port, int &chunk, int &offset);
private:
Vector<int> _elem_offset;
Vector<int> _elem_icount;
Vector<int> _chunks;
Vector<int> _offsets;
};
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,35 @@
// -*- c-basic-offset: 4; related-file-name: "../../../elements/standard/errorelement.cc" -*-
#ifndef CLICK_ERRORELEMENT_HH
#define CLICK_ERRORELEMENT_HH
#include <click/element.hh>
CLICK_DECLS
/*
* =c
* Error(...)
* =s debugging
* always fails
* =d
* The Error element always fails to initialize. It has any number of inputs
* and outputs, and accepts any configuration string without complaint. It is
* useful to prevent a router from initializing while avoiding
* spurious error messages about bad configuration strings or connections.
* =a Message
*/
class ErrorElement : public Element { public:
ErrorElement();
const char *class_name() const { return "Error"; }
const char *port_count() const { return "-/-"; }
const char *processing() const { return AGNOSTIC; }
const char *flow_code() const { return "x/y"; }
int configure(Vector<String> &, ErrorHandler *);
int initialize(ErrorHandler *);
};
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,71 @@
// -*- c-basic-offset: 4; related-file-name: "../../../elements/standard/portinfo.cc" -*-
#ifndef CLICK_PORTINFO_HH
#define CLICK_PORTINFO_HH
#include <click/element.hh>
CLICK_DECLS
/*
=c
PortInfo(NAME PORT[/PROTOCOL], ...)
=s information
stores named TCP/UDP port information
=io
None
=d
Lets you use mnemonic names for TCP and UDP ports. Each argument has the form
`NAME PORT[/PROTOCOL]', which associates the given PORT/PROTOCOL pair with the
NAME. If PROTOCOL is left off, the NAME applies to both TCP and UDP. For
example, in a configuration containing
PortInfo(ssh 22, http 80),
configuration strings can use C<ssh> and C<http> as mnemonics for the port
numbers 22 and 80, respectively.
PortInfo names are local with respect to compound elements. That is, names
created inside a compound element apply only within that compound element and
its subelements. For example:
PortInfo(src 10);
compound :: {
PortInfo(dst 100);
... -> UDPIPEncap(1.0.0.1, src, 2.0.0.1, dst) -> ... // OK
};
... -> UDPIPEncap(1.0.0.1, src, 2.0.0.1, dst) -> ...
// error: `dst' undefined
=n
If you do not define a port for a given name, PortInfo will use the default,
if any. At user level, PortInfo uses the L<getservbyname(3)> function to look
up ports by name. In the kernel, there are no default ports.
PortInfo will parse arguments containing more than one name, as `C<NAME
PORT/PROTOCOL NAME...>', and comments starting with `C<#>' are ignored. Thus,
lines from F</etc/services> can be used verbatim as PortInfo configuration
arguments.
=a
AddressInfo */
class PortInfo : public Element { public:
PortInfo();
const char *class_name() const { return "PortInfo"; }
int configure_phase() const { return CONFIGURE_PHASE_FIRST; }
int configure(Vector<String> &, ErrorHandler *);
};
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,104 @@
// -*- c-basic-offset: 4; related-file-name: "../../../elements/standard/scheduleinfo.cc" -*-
#ifndef CLICK_SCHEDULEINFO_HH
#define CLICK_SCHEDULEINFO_HH
#include <click/element.hh>
CLICK_DECLS
/*
=c
ScheduleInfo(ELEMENT PARAM, ...)
=s information
specifies scheduling parameters
=io
None
=d
Provides scheduling parameters for specified elements. Each configuration
argument has the form `ELEMENT PARAM', meaning that the element
named ELEMENT has scheduling parameter PARAM. Scheduling
parameters are real numbers that set how often one element should be
scheduled in relation to another. For example,
if elements A and B have
scheduling parameters 2 and 0.5, respectively, then A will be scheduled
2/0.5 = 4 times as often as B. The default scheduling parameter is 1.
ScheduleInfo elements inside a compound element can specify scheduling
parameters for that compound's components.
Outer ScheduleInfo elements
can specify a ``scheduling parameter'' for the compound
element as a whole. This ``scheduling parameter'' is really a scaling
factor affecting the compound's components. For example, consider this
configuration,
elementclass Compound {
i :: InfiniteSource -> output;
ScheduleInfo(i 0.5);
}
c :: Compound -> Discard;
ScheduleInfo(c 4);
which is the same as the following configuration, after compound elements
are expanded.
c/i :: InfiniteSource -> Discard@3 :: Discard;
c/ScheduleInfo@2 :: ScheduleInfo(i 0.5);
ScheduleInfo@4 :: ScheduleInfo(c 4);
The name of the first ScheduleInfo element starts with `c/', so it is
used to look up scheduling parameters for elements named `c/I<whatever>'.
V<>(This includes all components of the compound element `c'.)
The second ScheduleInfo element, however, has no slash in its name,
so it is used to look up all scheduling parameters,
including scaling factors for compound elements.
The InfiniteSource's final scaling parameter will be 2:
the scaling factor 4 times the local scheduling parameter 0.5.
An outer ScheduleInfo element can override local scheduling parameters.
For example, if the second ScheduleInfo element above was
ScheduleInfo@4 :: ScheduleInfo(c 4, c/i 10.5)
then the InfiniteSource's final scaling parameter would be 10.5.
*/
class ScheduleInfo : public Element { public:
enum { FRAC_BITS = 10 };
ScheduleInfo();
const char* class_name() const { return "ScheduleInfo"; }
int configure_phase() const { return CONFIGURE_PHASE_INFO; }
int configure(Vector<String>&, ErrorHandler*);
bool query(const String&, int&) const;
bool query_prefixes(const String&, int&, String&) const;
static int query(Element*, ErrorHandler*);
static void initialize_task(Element*, Task*, bool sched, ErrorHandler*);
static void initialize_task(Element*, Task*, ErrorHandler*);
static void join_scheduler(Element*, Task*, ErrorHandler*);
};
inline void
ScheduleInfo::initialize_task(Element* e, Task* t, ErrorHandler* errh)
{
initialize_task(e, t, true, errh);
}
inline void
ScheduleInfo::join_scheduler(Element* e, Task* t, ErrorHandler* errh)
{
initialize_task(e, t, true, errh);
}
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,123 @@
// -*- c-basic-offset: 4 -*-
#ifndef CLICK_STORAGE_HH
#define CLICK_STORAGE_HH
#include <click/machine.hh>
#include <click/atomic.hh>
CLICK_DECLS
class Packet;
class Storage { public:
typedef uint32_t index_type;
typedef int32_t signed_index_type;
static const index_type invalid_index = (index_type) -1;
Storage() : _head(0), _tail(0) { }
operator bool() const { return _head != _tail; }
bool empty() const { return _head == _tail; }
int size() const;
int size(index_type head, index_type tail) const;
int capacity() const { return _capacity; }
index_type head() const { return _head; }
index_type tail() const { return _tail; }
index_type next_i(index_type i) const {
return (i!=_capacity ? i+1 : 0);
}
index_type prev_i(index_type i) const {
return (i!=0 ? i-1 : _capacity);
}
// to be used with care
void set_capacity(index_type c) { _capacity = c; }
inline void set_head(index_type h); // acquire barrier (read pkt)
inline void set_tail(index_type t); // release barrier (write pkt)
inline void set_head_release(index_type h); // release barrier (LIFO)
inline void set_tail_acquire(index_type t); // acquire barrier (LIFO)
inline index_type reserve_tail_atomic();
static inline void packet_memory_barrier(Packet* volatile& packet,
volatile index_type& index)
__attribute__((deprecated));
inline void packet_memory_barrier(Packet* volatile& packet)
__attribute__((deprecated));
protected:
index_type _capacity;
private:
volatile index_type _head;
volatile index_type _tail;
};
inline int
Storage::size(index_type head, index_type tail) const
{
index_type x = tail - head;
return (signed_index_type(x) >= 0 ? x : _capacity + x + 1);
}
inline int
Storage::size() const
{
return size(_head, _tail);
}
inline void
Storage::set_head(index_type h)
{
click_read_fence();
_head = h;
}
inline void
Storage::set_tail(index_type t)
{
click_write_fence();
_tail = t;
}
inline void
Storage::set_head_release(index_type h)
{
click_write_fence();
_head = h;
}
inline void
Storage::set_tail_acquire(index_type t)
{
click_read_fence();
_tail = t;
}
inline Storage::index_type
Storage::reserve_tail_atomic()
{
index_type t, nt;
do {
t = _tail;
nt = next_i(t);
if (nt == _head)
return invalid_index;
} while (atomic_uint32_t::compare_swap(_tail, t, nt) != t);
return t;
}
inline void
Storage::packet_memory_barrier(Packet* volatile& packet, volatile index_type& index)
{
__asm__ volatile("" : : "m" (packet), "m" (index));
}
inline void
Storage::packet_memory_barrier(Packet * volatile &packet)
{
__asm__ volatile("" : : "m" (packet), "m" (_head), "m" (_tail));
}
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,18 @@
// -*- c-basic-offset: 4 -*-
#ifndef CLICK_THREADSCHED_HH
#define CLICK_THREADSCHED_HH
CLICK_DECLS
class ThreadSched { public:
enum { THREAD_QUIESCENT = -1, THREAD_UNKNOWN = -1000 };
ThreadSched() { }
virtual ~ThreadSched() { }
virtual int initial_home_thread_id(const Element *e);
};
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,624 @@
// -*- c-basic-offset: 4; related-file-name: "../../lib/straccum.cc" -*-
#ifndef CLICK_STRACCUM_HH
#define CLICK_STRACCUM_HH
#include <click/glue.hh>
#include <click/string.hh>
#ifdef CLICK_LINUXMODULE
# include <click/cxxprotect.h>
CLICK_CXX_PROTECT
# include <asm/string.h>
CLICK_CXX_UNPROTECT
# include <click/cxxunprotect.h>
#elif defined(CLICK_BSDMODULE)
# include <sys/systm.h>
#else /* User-space */
# include <string.h>
#endif
#if __GNUC__ > 4
# define CLICK_SNPRINTF_ATTR __attribute__((__format__(__printf__, 3, 4)))
#else
# define CLICK_SNPRINTF_ATTR /* nothing */
#endif
CLICK_DECLS
/** @file <click/straccum.hh>
@brief Click's StringAccum class, used to construct Strings efficiently from pieces.
*/
class StringAccum { public:
typedef const char *const_iterator;
typedef char *iterator;
typedef int (StringAccum::*unspecified_bool_type)() const;
inline StringAccum();
explicit inline StringAccum(int capacity);
inline StringAccum(const String &str);
inline StringAccum(const StringAccum &x);
#if HAVE_CXX_RVALUE_REFERENCES
inline StringAccum(StringAccum &&x);
#endif
inline ~StringAccum();
inline StringAccum &operator=(const StringAccum &x);
#if HAVE_CXX_RVALUE_REFERENCES
inline StringAccum &operator=(StringAccum &&x);
#endif
inline const char *data() const;
inline char *data();
inline int length() const;
inline int capacity() const;
const char *c_str();
inline operator unspecified_bool_type() const;
inline bool empty() const;
inline bool operator!() const;
inline const_iterator begin() const;
inline iterator begin();
inline const_iterator end() const;
inline iterator end();
inline char operator[](int i) const;
inline char &operator[](int i);
inline char front() const;
inline char &front();
inline char back() const;
inline char &back();
inline bool out_of_memory() const;
void assign_out_of_memory();
inline void clear();
inline char *reserve(int n);
inline void set_length(int len);
int resize(int len);
inline void adjust_length(int delta);
inline char *extend(int nadjust, int nreserve = 0);
inline void pop_back(int n = 1);
inline void append(char c);
inline void append(unsigned char c);
inline bool append_utf8(int ch);
inline void append(const char *cstr);
inline void append(const char *s, int len);
inline void append(const unsigned char *s, int len);
inline void append(const char *first, const char *last);
inline void append(const unsigned char *first, const unsigned char *last);
void append_fill(int c, int len);
void append_numeric(String::intmax_t x, int base = 10, bool uppercase = true);
void append_numeric(String::uintmax_t x, int base = 10, bool uppercase = true);
StringAccum &snprintf(int n, const char *format, ...) CLICK_SNPRINTF_ATTR;
String take_string();
void swap(StringAccum &x);
// see also operator<< declarations below
inline void forward(int delta) CLICK_DEPRECATED;
private:
enum {
MEMO_SPACE = String::MEMO_SPACE
};
struct rep_t {
unsigned char *s;
int len;
int cap;
rep_t()
: s(reinterpret_cast<unsigned char *>(const_cast<char *>(String::empty_data()))),
len(0), cap(0) {
}
explicit rep_t(uninitialized_type) {
}
};
rep_t r_;
char *grow(int);
char *hard_extend(int nadjust, int nreserve);
void hard_append(const char *s, int len);
void hard_append_cstr(const char *cstr);
bool append_utf8_hard(int ch);
friend StringAccum &operator<<(StringAccum &sa, const String &str);
#if HAVE_PERMSTRING
friend StringAccum &operator<<(StringAccum &sa, PermString s);
#endif
};
inline StringAccum &operator<<(StringAccum &sa, char c);
inline StringAccum &operator<<(StringAccum &sa, unsigned char c);
inline StringAccum &operator<<(StringAccum &sa, const char *cstr);
inline StringAccum &operator<<(StringAccum &sa, const String &s);
inline StringAccum &operator<<(StringAccum &sa, const StringAccum &x);
inline StringAccum &operator<<(StringAccum &sa, bool x);
inline StringAccum &operator<<(StringAccum &sa, short x);
inline StringAccum &operator<<(StringAccum &sa, unsigned short x);
inline StringAccum &operator<<(StringAccum &sa, int x);
inline StringAccum &operator<<(StringAccum &sa, unsigned x);
StringAccum &operator<<(StringAccum &sa, long x);
StringAccum &operator<<(StringAccum &sa, unsigned long x);
#if HAVE_LONG_LONG
inline StringAccum &operator<<(StringAccum &sa, long long x);
inline StringAccum &operator<<(StringAccum &sa, unsigned long long x);
#endif
#if HAVE_INT64_TYPES && !HAVE_INT64_IS_LONG && !HAVE_INT64_IS_LONG_LONG
inline StringAccum &operator<<(StringAccum &sa, int64_t x);
inline StringAccum &operator<<(StringAccum &sa, uint64_t x);
#endif
#if defined(CLICK_USERLEVEL) || defined(CLICK_TOOL) || defined(CLICK_MINIOS)
StringAccum &operator<<(StringAccum &sa, double x);
#endif
StringAccum &operator<<(StringAccum &sa, const void *ptr);
/** @brief Construct an empty StringAccum (with length 0). */
inline StringAccum::StringAccum() {
}
/** @brief Construct a StringAccum with room for at least @a capacity
characters.
@param capacity initial capacity
If @a capacity == 0, the StringAccum is created empty. If @a capacity is
too large (so that @a capacity bytes of memory can't be allocated), the
StringAccum falls back to a smaller capacity (possibly zero). */
inline StringAccum::StringAccum(int capacity) {
assert(capacity >= 0);
unsigned char *s;
if (capacity
&& (s = (unsigned char *) CLICK_LALLOC(capacity + MEMO_SPACE))) {
r_.s = s + MEMO_SPACE;
r_.cap = capacity;
}
}
/** @brief Construct a StringAccum containing the characters in @a str. */
inline StringAccum::StringAccum(const String &str) {
append(str.begin(), str.end());
}
/** @brief Construct a StringAccum containing a copy of @a x. */
inline StringAccum::StringAccum(const StringAccum &x) {
append(x.data(), x.length());
}
#if HAVE_CXX_RVALUE_REFERENCES
/** @brief Move-construct a StringAccum from @a x. */
inline StringAccum::StringAccum(StringAccum &&x)
: r_(x.r_) {
x.r_.cap = 0;
}
#endif
/** @brief Destroy a StringAccum, freeing its memory. */
inline StringAccum::~StringAccum() {
if (r_.cap > 0)
CLICK_LFREE(r_.s - MEMO_SPACE, r_.cap + MEMO_SPACE);
}
/** @brief Return the contents of the StringAccum.
@return The StringAccum's contents.
The returned data() value points to length() bytes of writable memory
(unless the StringAccum itself is const). */
inline const char *StringAccum::data() const {
return reinterpret_cast<const char *>(r_.s);
}
/** @overload */
inline char *StringAccum::data() {
return reinterpret_cast<char *>(r_.s);
}
/** @brief Return the length of the StringAccum. */
inline int StringAccum::length() const {
return r_.len;
}
/** @brief Return the StringAccum's current capacity.
The capacity is the maximum length the StringAccum can hold without
incurring a memory allocation. Returns -1 for out-of-memory
StringAccums. */
inline int StringAccum::capacity() const {
return r_.cap;
}
/** @brief Return an iterator for the first character in the StringAccum.
StringAccum iterators are simply pointers into string data, so they are
quite efficient. @sa StringAccum::data */
inline StringAccum::const_iterator StringAccum::begin() const {
return reinterpret_cast<char *>(r_.s);
}
/** @overload */
inline StringAccum::iterator StringAccum::begin() {
return reinterpret_cast<char *>(r_.s);
}
/** @brief Return an iterator for the end of the StringAccum.
The return value points one character beyond the last character in the
StringAccum. */
inline StringAccum::const_iterator StringAccum::end() const {
return reinterpret_cast<char *>(r_.s + r_.len);
}
/** @overload */
inline StringAccum::iterator StringAccum::end() {
return reinterpret_cast<char *>(r_.s + r_.len);
}
/** @brief Test if the StringAccum contains characters. */
inline StringAccum::operator unspecified_bool_type() const {
return r_.len != 0 ? &StringAccum::capacity : 0;
}
/** @brief Test if the StringAccum is empty.
Returns true iff length() == 0. */
inline bool StringAccum::operator!() const {
return r_.len == 0;
}
/** @brief Test if the StringAccum is empty. */
inline bool StringAccum::empty() const {
return r_.len == 0;
}
/** @brief Test if the StringAccum is out-of-memory. */
inline bool StringAccum::out_of_memory() const {
return unlikely(r_.cap < 0);
}
/** @brief Return the <a>i</a>th character in the string.
@param i character index
@pre 0 <= @a i < length() */
inline char StringAccum::operator[](int i) const {
assert((unsigned) i < (unsigned) r_.len);
return static_cast<char>(r_.s[i]);
}
/** @brief Return a reference to the <a>i</a>th character in the string.
@param i character index
@pre 0 <= @a i < length() */
inline char &StringAccum::operator[](int i) {
assert((unsigned) i < (unsigned) r_.len);
return reinterpret_cast<char &>(r_.s[i]);
}
/** @brief Return the first character in the string.
@pre length() > 0 */
inline char StringAccum::front() const {
assert(r_.len > 0);
return static_cast<char>(r_.s[0]);
}
/** @brief Return a reference to the first character in the string.
@pre length() > 0 */
inline char &StringAccum::front() {
assert(r_.len > 0);
return reinterpret_cast<char &>(r_.s[0]);
}
/** @brief Return the last character in the string.
@pre length() > 0 */
inline char StringAccum::back() const {
assert(r_.len > 0);
return static_cast<char>(r_.s[r_.len - 1]);
}
/** @brief Return a reference to the last character in the string.
@pre length() > 0 */
inline char &StringAccum::back() {
assert(r_.len > 0);
return reinterpret_cast<char &>(r_.s[r_.len - 1]);
}
/** @brief Clear the StringAccum's comments.
All characters in the StringAccum are erased. Also resets the
StringAccum's out-of-memory status. */
inline void StringAccum::clear() {
if (r_.cap < 0)
r_.cap = 0;
r_.len = 0;
}
/** @brief Reserve space for at least @a n characters.
@return a pointer to at least @a n characters, or null if allocation
fails
@pre @a n >= 0
reserve() does not change the string's length(), only its capacity(). In
a frequent usage pattern, code calls reserve(), passing an upper bound
on the characters that could be written by a series of operations. After
writing into the returned buffer, adjust_length() is called to account
for the number of characters actually written. */
inline char *StringAccum::reserve(int n) {
assert(n >= 0);
if (r_.len + n <= r_.cap)
return reinterpret_cast<char *>(r_.s + r_.len);
else
return grow(r_.len + n);
}
/** @brief Set the StringAccum's length to @a len.
@param len new length in characters
@pre 0 <= @a len <= capacity()
@sa adjust_length */
inline void StringAccum::set_length(int len) {
assert(len >= 0 && r_.len <= r_.cap);
r_.len = len;
}
/** @brief Adjust the StringAccum's length.
@param delta length adjustment
@pre If @a delta > 0, then length() + @a delta <= capacity().
If @a delta < 0, then length() + delta >= 0.
The StringAccum's length after adjust_length(@a delta) equals its old
length plus @a delta. Generally adjust_length() is used after a call to
reserve(). @sa set_length */
inline void StringAccum::adjust_length(int delta) {
assert(r_.len + delta >= 0 && r_.len + delta <= r_.cap);
r_.len += delta;
}
/** @brief Reserve space and adjust length in one operation.
@param nadjust number of characters to reserve and adjust length
@param nreserve additional characters to reserve
@pre @a nadjust >= 0 and @a nreserve >= 0
This operation combines the effects of reserve(@a nadjust + @a nreserve)
and adjust_length(@a nadjust). Returns the result of the reserve()
call. */
inline char *StringAccum::extend(int nadjust, int nreserve) {
#if CLICK_OPTIMIZE_SIZE || __OPTIMIZE_SIZE__
return hard_extend(nadjust, nreserve);
#else
assert(nadjust >= 0 && nreserve >= 0);
if (r_.len + nadjust + nreserve <= r_.cap) {
char *x = reinterpret_cast<char *>(r_.s + r_.len);
r_.len += nadjust;
return x;
} else
return hard_extend(nadjust, nreserve);
#endif
}
/** @brief Remove characters from the end of the StringAccum.
@param n number of characters to remove
@pre @a n >= 0 and @a n <= length()
Same as adjust_length(-@a n). */
inline void StringAccum::pop_back(int n) {
assert(n >= 0 && r_.len >= n);
r_.len -= n;
}
/** @brief Append character @a c to the StringAccum.
@param c character to append */
inline void StringAccum::append(char c) {
if (r_.len < r_.cap || grow(r_.len))
r_.s[r_.len++] = c;
}
/** @overload */
inline void StringAccum::append(unsigned char c) {
append(static_cast<char>(c));
}
/** @brief Append the first @a len characters of @a s to this StringAccum.
@param s data to append
@param len length of data
@pre @a len >= 0 */
inline void StringAccum::append(const char *s, int len) {
#if CLICK_OPTIMIZE_SIZE || __OPTIMIZE_SIZE__
hard_append(s, len);
#else
assert(len >= 0);
if (r_.len + len <= r_.cap) {
memcpy(r_.s + r_.len, s, len);
r_.len += len;
} else
hard_append(s, len);
#endif
}
/** @overload */
inline void StringAccum::append(const unsigned char *s, int len) {
append(reinterpret_cast<const char *>(s), len);
}
/** @brief Append the null-terminated C string @a s to this StringAccum.
@param s data to append */
inline void StringAccum::append(const char *cstr) {
if (CLICK_CONSTANT_CSTR(cstr))
append(cstr, strlen(cstr));
else
hard_append_cstr(cstr);
}
/** @brief Append the data from @a first to @a last to the end of this
StringAccum.
Does nothing if @a first >= @a last. */
inline void StringAccum::append(const char *first, const char *last) {
if (first < last)
append(first, last - first);
}
/** @overload */
inline void StringAccum::append(const unsigned char *first, const unsigned char *last) {
if (first < last)
append(first, last - first);
}
/** @brief Append Unicode character @a ch encoded in UTF-8.
@return true if character was valid.
Appends nothing if @a ch is not a valid Unicode character. */
inline bool StringAccum::append_utf8(int ch) {
if (unlikely(ch <= 0))
return false;
else if (likely(ch <= 0x7F)) {
append(static_cast<char>(ch));
return true;
} else
return append_utf8_hard(ch);
}
/** @brief Assign this StringAccum to @a x. */
inline StringAccum &StringAccum::operator=(const StringAccum &x) {
if (&x != this) {
if (out_of_memory())
r_.cap = 0;
r_.len = 0;
append(x.data(), x.length());
}
return *this;
}
#if HAVE_CXX_RVALUE_REFERENCES
/** @brief Move-assign this StringAccum to @a x. */
inline StringAccum &StringAccum::operator=(StringAccum &&x) {
x.swap(*this);
return *this;
}
#endif
/** @cond never */
/** @brief Adjust the StringAccum's length (deprecated).
@param delta length adjustment
@deprecated Use adjust_length() instead. */
inline void StringAccum::forward(int delta) {
adjust_length(delta);
}
/** @endcond never */
/** @relates StringAccum
@brief Append character @a c to StringAccum @a sa.
@return @a sa
@note Same as @a sa.append(@a c). */
inline StringAccum &operator<<(StringAccum &sa, char c) {
sa.append(c);
return sa;
}
/** @relates StringAccum
@brief Append character @a c to StringAccum @a sa.
@return @a sa
@note Same as @a sa.append(@a c). */
inline StringAccum &operator<<(StringAccum &sa, unsigned char c) {
sa.append(c);
return sa;
}
/** @relates StringAccum
@brief Append null-terminated C string @a cstr to StringAccum @a sa.
@return @a sa
@note Same as @a sa.append(@a cstr). */
inline StringAccum &operator<<(StringAccum &sa, const char *cstr) {
sa.append(cstr);
return sa;
}
/** @relates StringAccum
@brief Append "true" or "false" to @a sa, depending on @a x.
@return @a sa */
inline StringAccum &operator<<(StringAccum &sa, bool x) {
sa.append(String::bool_data + (-x & 6), 5 - x);
return sa;
}
/** @relates StringAccum
@brief Append decimal representation of @a x to @a sa.
@return @a sa */
inline StringAccum &operator<<(StringAccum &sa, short x) {
return sa << static_cast<long>(x);
}
/** @overload */
inline StringAccum &operator<<(StringAccum &sa, unsigned short x) {
return sa << static_cast<unsigned long>(x);
}
/** @overload */
inline StringAccum &operator<<(StringAccum &sa, int x) {
return sa << static_cast<long>(x);
}
/** @overload */
inline StringAccum &operator<<(StringAccum &sa, unsigned x) {
return sa << static_cast<unsigned long>(x);
}
#if HAVE_LONG_LONG
/** @overload */
inline StringAccum &operator<<(StringAccum &sa, long long x) {
sa.append_numeric(static_cast<String::intmax_t>(x));
return sa;
}
/** @overload */
inline StringAccum &operator<<(StringAccum &sa, unsigned long long x) {
sa.append_numeric(static_cast<String::uintmax_t>(x));
return sa;
}
#endif
#if HAVE_INT64_TYPES && !HAVE_INT64_IS_LONG && !HAVE_INT64_IS_LONG_LONG
/** @overload */
inline StringAccum &operator<<(StringAccum &sa, int64_t x) {
sa.append_numeric(static_cast<String::intmax_t>(x));
return sa;
}
/** @overload */
inline StringAccum &operator<<(StringAccum &sa, uint64_t x) {
sa.append_numeric(static_cast<String::uintmax_t>(x));
return sa;
}
#endif
/** @relates StringAccum
@brief Append the contents of @a str to @a sa.
@return @a sa */
inline StringAccum &operator<<(StringAccum &sa, const String &str) {
sa.append(str.data(), str.length());
return sa;
}
/** @relates StringAccum
@brief Append the contents of @a x to @a sa.
@return @a sa */
inline StringAccum &operator<<(StringAccum &sa, const StringAccum &x) {
sa.append(x.begin(), x.end());
return sa;
}
inline void click_swap(StringAccum &a, StringAccum &b) {
a.swap(b);
}
inline void assign_consume(StringAccum &a, StringAccum &b) {
a.swap(b);
}
#undef CLICK_SNPRINTF_ATTR
CLICK_ENDDECLS
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,568 @@
// -*- c-basic-offset: 4 -*-
#ifndef CLICK_SYNC_HH
#define CLICK_SYNC_HH
#include <click/machine.hh>
#include <click/glue.hh>
#include <click/atomic.hh>
#if CLICK_LINUXMODULE || (CLICK_USERLEVEL && HAVE_MULTITHREAD)
# define CLICK_MULTITHREAD_SPINLOCK 1
#endif
#if CLICK_USERLEVEL && !NDEBUG
# define SPINLOCK_ASSERTLEVEL "<-999>"
#else
# define SPINLOCK_ASSERTLEVEL "<1>"
#endif
CLICK_DECLS
/** @file <click/sync.hh>
* @brief Classes for synchronizing among multiple CPUs, particularly in the
* Linux kernel.
*/
/** @class Spinlock
* @brief A recursive spinlock for SMP Click threads.
*
* The Spinlock class abstracts a recursive spinlock, or polling mutex, in SMP
* Click. This is a type of mutual-exclusion lock in which acquiring the lock
* is a polling operation (basically a "while (lock.acquired()) do nothing;"
* loop). Spinlocks can be used to synchronize access to shared data among
* multiple Click SMP threads. Spinlocks should not be held for long periods
* of time: use them for quick updates and such.
*
* Spinlock operations do nothing unless Click was compiled with SMP support
* (with --enable-multithread). Therefore, Spinlock should not be used to,
* for example, synchronize handlers with main element threads. See also
* SpinlockIRQ.
*
* The main Spinlock operations are acquire(), which acquires the lock, and
* release(), which releases the lock. attempt() acquires the lock only if it
* can be acquired instantaneously.
*
* It is OK for a thread to acquire a lock it has already acquired, but you
* must release it as many times as you have acquired it.
*
* @sa SimpleSpinlock, SpinlockIRQ
*/
class Spinlock { public:
inline Spinlock();
inline ~Spinlock();
inline void acquire();
inline void release();
inline bool attempt();
inline bool nested() const;
#if CLICK_MULTITHREAD_SPINLOCK
private:
atomic_uint32_t _lock;
int32_t _depth;
click_processor_t _owner;
#endif
};
/** @brief Create a Spinlock. */
inline
Spinlock::Spinlock()
#if CLICK_MULTITHREAD_SPINLOCK
: _depth(0), _owner(click_invalid_processor())
#endif
{
#if CLICK_MULTITHREAD_SPINLOCK
_lock = 0;
#endif
}
inline
Spinlock::~Spinlock()
{
#if CLICK_MULTITHREAD_SPINLOCK
if (_depth != 0)
click_chatter(SPINLOCK_ASSERTLEVEL "Spinlock::~Spinlock(): assertion \"_depth == 0\" failed");
#endif
}
/** @brief Acquires the Spinlock.
*
* On return, this thread has acquired the lock. The function will spin
* indefinitely until the lock is acquired. It is OK to acquire a lock you
* have already acquired, but you must release it as many times as you have
* acquired it.
*/
inline void
Spinlock::acquire()
{
#if CLICK_MULTITHREAD_SPINLOCK
click_processor_t my_cpu = click_get_processor();
if (_owner != my_cpu) {
while (_lock.swap(1) != 0)
do {
click_relax_fence();
} while (_lock != 0);
_owner = my_cpu;
}
_depth++;
#endif
}
/** @brief Attempts to acquire the Spinlock.
* @return True iff the Spinlock was acquired.
*
* This function will acquire the lock and return true only if the Spinlock
* can be acquired right away, without retries.
*/
inline bool
Spinlock::attempt()
{
#if CLICK_MULTITHREAD_SPINLOCK
click_processor_t my_cpu = click_get_processor();
if (_owner != my_cpu) {
if (_lock.swap(1) != 0) {
click_put_processor();
return false;
}
_owner = my_cpu;
}
_depth++;
return true;
#else
return true;
#endif
}
/** @brief Releases the Spinlock.
*
* The Spinlock must have been previously acquired by either Spinlock::acquire
* or Spinlock::attempt.
*/
inline void
Spinlock::release()
{
#if CLICK_MULTITHREAD_SPINLOCK
if (unlikely(_owner != click_current_processor()))
click_chatter(SPINLOCK_ASSERTLEVEL "Spinlock::release(): assertion \"owner == click_current_processor()\" failed");
if (likely(_depth > 0)) {
if (--_depth == 0) {
_owner = click_invalid_processor();
_lock = 0;
}
} else
click_chatter(SPINLOCK_ASSERTLEVEL "Spinlock::release(): assertion \"_depth > 0\" failed");
click_put_processor();
#endif
}
/** @brief Returns true iff the Spinlock has been acquired more than once by
* the current thread.
*/
inline bool
Spinlock::nested() const
{
#if CLICK_MULTITHREAD_SPINLOCK
return _depth > 1;
#else
return false;
#endif
}
/** @class SimpleSpinlock
* @brief A non-recursive spinlock for SMP Click threads.
*
* The Spinlock class abstracts a non-recursive spinlock, or polling mutex, in
* SMP Click. This is a type of mutual-exclusion lock in which acquiring the
* lock is a polling operation (basically a "while (lock.acquired()) do
* nothing;" loop). Spinlocks can be used to synchronize access to shared
* data among multiple Click SMP threads. Spinlocks should not be held for
* long periods of time: use them for quick updates and such.
*
* Spinlock operations do nothing unless Click was compiled with SMP support
* (with --enable-multithread). Therefore, Spinlock should not be used to,
* for example, synchronize handlers with main element threads. See also
* SpinlockIRQ.
*
* The main Spinlock operations are acquire(), which acquires the lock, and
* release(), which releases the lock. attempt() acquires the lock only if it
* can be acquired instantaneously.
*
* It is NOT OK for a thread to acquire a lock it has already acquired.
*
* @sa Spinlock, SpinlockIRQ
*/
class SimpleSpinlock { public:
inline SimpleSpinlock();
inline ~SimpleSpinlock();
inline void acquire();
inline void release();
inline bool attempt();
#if CLICK_LINUXMODULE
private:
spinlock_t _lock;
#elif CLICK_MULTITHREAD_SPINLOCK
private:
atomic_uint32_t _lock;
#endif
};
/** @brief Create a SimpleSpinlock. */
inline
SimpleSpinlock::SimpleSpinlock()
{
#if CLICK_LINUXMODULE
spin_lock_init(&_lock);
#elif CLICK_MULTITHREAD_SPINLOCK
_lock = 0;
#endif
}
inline
SimpleSpinlock::~SimpleSpinlock()
{
}
/** @brief Acquires the SimpleSpinlock.
*
* On return, this thread has acquired the lock. The function will spin
* indefinitely until the lock is acquired.
*/
inline void
SimpleSpinlock::acquire()
{
#if CLICK_LINUXMODULE
spin_lock(&_lock);
#elif CLICK_MULTITHREAD_SPINLOCK
while (_lock.swap(1) != 0)
do {
click_relax_fence();
} while (_lock != 0);
#endif
}
/** @brief Attempts to acquire the SimpleSpinlock.
* @return True iff the SimpleSpinlock was acquired.
*
* This function will acquire the lock and return true only if the
* SimpleSpinlock can be acquired right away, without retries.
*/
inline bool
SimpleSpinlock::attempt()
{
#if CLICK_LINUXMODULE
return spin_trylock(&_lock);
#elif CLICK_MULTITHREAD_SPINLOCK
return _lock.swap(1) == 0;
#else
return true;
#endif
}
/** @brief Releases the SimpleSpinlock.
*
* The SimpleSpinlock must have been previously acquired by either
* SimpleSpinlock::acquire or SimpleSpinlock::attempt.
*/
inline void
SimpleSpinlock::release()
{
#if CLICK_LINUXMODULE
spin_unlock(&_lock);
#elif CLICK_MULTITHREAD_SPINLOCK
_lock = 0;
#endif
}
/** @class SpinlockIRQ
* @brief A spinlock that disables interrupts.
*
* The SpinlockIRQ class abstracts a spinlock, or polling mutex, that also
* turns off interrupts. Spinlocks are a type of mutual-exclusion lock in
* which acquiring the lock is a polling operation (basically a "while
* (lock.acquired()) do nothing;" loop). The SpinlockIRQ variant can be used
* to protect Click data structures from interrupts and from other threads.
* Very few objects in Click need this protection; the Click Master object,
* which protects the task list, uses it, but that's hidden from users.
* Spinlocks should not be held for long periods of time: use them for quick
* updates and such.
*
* In the Linux kernel, SpinlockIRQ is equivalent to a combination of
* local_irq_save and the spinlock_t type.
*
* The SpinlockIRQ operations are acquire(), which acquires the lock, and
* release(), which releases the lock.
*
* It is NOT OK for a SpinlockIRQ thread to acquire a lock it has already
* acquired.
*/
class SpinlockIRQ { public:
inline SpinlockIRQ();
#if CLICK_LINUXMODULE
typedef unsigned long flags_t;
#else
typedef int flags_t;
#endif
inline flags_t acquire() CLICK_ALWAYS_INLINE;
inline void release(flags_t) CLICK_ALWAYS_INLINE;
#if CLICK_LINUXMODULE
private:
spinlock_t _lock;
#elif CLICK_USERLEVEL && HAVE_MULTITHREAD
private:
Spinlock _lock;
#endif
};
/** @brief Creates a SpinlockIRQ. */
inline
SpinlockIRQ::SpinlockIRQ()
{
#if CLICK_LINUXMODULE
spin_lock_init(&_lock);
#endif
}
/** @brief Acquires the SpinlockIRQ.
* @return The current state of the interrupt flags.
*/
inline SpinlockIRQ::flags_t
SpinlockIRQ::acquire()
{
#if CLICK_LINUXMODULE
flags_t flags;
spin_lock_irqsave(&_lock, flags);
return flags;
#elif CLICK_USERLEVEL && HAVE_MULTITHREAD
_lock.acquire();
return 0;
#else
return 0;
#endif
}
/** @brief Releases the SpinlockIRQ.
* @param flags The value returned by SpinlockIRQ::acquire().
*/
inline void
SpinlockIRQ::release(flags_t flags)
{
#if CLICK_LINUXMODULE
spin_unlock_irqrestore(&_lock, flags);
#elif CLICK_USERLEVEL && HAVE_MULTITHREAD
(void) flags;
_lock.release();
#else
(void) flags;
#endif
}
// read-write lock
//
// on read: acquire local read lock
// on write: acquire every read lock
//
// alternatively, we could use a read counter and a write lock. we don't do
// that because we'd like to avoid a cache miss for read acquires. this makes
// reads very fast, and writes more expensive
/** @class ReadWriteLock
* @brief A read/write lock.
*
* The ReadWriteLock class abstracts a read/write lock in SMP Click. Multiple
* SMP Click threads can hold read locks simultaneously, but if any thread
* holds a write lock, then no other thread holds any kind of lock. The
* read/write lock is implemented with Spinlock objects, so acquiring a lock
* is a polling operation. ReadWriteLocks can be used to synchronize access
* to shared data among multiple Click SMP threads. ReadWriteLocks should not
* be held for long periods of time.
*
* ReadWriteLock operations do nothing unless Click was compiled with
* --enable-multithread. Therefore, ReadWriteLock should not be used to, for
* example, synchronize handlers with main element threads.
*
* The main ReadWriteLock operations are acquire_read() and acquire_write(),
* which acquire the lock for reading or writing, respectively, and
* release_read() and release_write(), which similarly release the lock.
* attempt_read() and attempt_write() acquire the lock only if it can be
* acquired instantaneously.
*
* It is OK for a thread to acquire a lock it has already acquired, but you
* must release it as many times as you have acquired it.
*
* ReadWriteLock objects are relatively large in terms of memory usage; don't
* create too many of them.
*/
class ReadWriteLock { public:
inline ReadWriteLock();
#if CLICK_LINUXMODULE && defined(CONFIG_SMP)
inline ~ReadWriteLock();
#endif
inline void acquire_read();
inline bool attempt_read();
inline void release_read();
inline void acquire_write();
inline bool attempt_write();
inline void release_write();
#if CLICK_LINUXMODULE && defined(CONFIG_SMP)
private:
// allocate a cache line for every member
struct lock_t {
Spinlock _lock;
unsigned char reserved[L1_CACHE_BYTES - sizeof(Spinlock)];
} *_l;
#endif
};
/** @brief Creates a ReadWriteLock. */
inline
ReadWriteLock::ReadWriteLock()
{
#if CLICK_LINUXMODULE && defined(CONFIG_SMP)
_l = new lock_t[num_possible_cpus()];
#endif
}
#if CLICK_LINUXMODULE && defined(CONFIG_SMP)
inline
ReadWriteLock::~ReadWriteLock()
{
delete[] _l;
}
#endif
/** @brief Acquires the ReadWriteLock for reading.
*
* On return, this thread has acquired the lock for reading. The function
* will spin indefinitely until the lock is acquired. It is OK to acquire a
* lock you have already acquired, but you must release it as many times as
* you have acquired it.
*
* @sa Spinlock::acquire
*/
inline void
ReadWriteLock::acquire_read()
{
#if CLICK_LINUXMODULE && defined(CONFIG_SMP)
click_processor_t my_cpu = click_get_processor();
_l[my_cpu]._lock.acquire();
#endif
}
/** @brief Attempts to acquire the ReadWriteLock for reading.
* @return True iff the ReadWriteLock was acquired.
*
* This function will acquire the lock for reading and return true only if the
* ReadWriteLock can be acquired right away, without retries.
*/
inline bool
ReadWriteLock::attempt_read()
{
#if CLICK_LINUXMODULE && defined(CONFIG_SMP)
click_processor_t my_cpu = click_get_processor();
bool result = _l[my_cpu]._lock.attempt();
if (!result)
click_put_processor();
return result;
#else
return true;
#endif
}
/** @brief Releases the ReadWriteLock for reading.
*
* The ReadWriteLock must have been previously acquired by either
* ReadWriteLock::acquire_read or ReadWriteLock::attempt_read. Do not call
* release_read() on a lock that was acquired for writing.
*/
inline void
ReadWriteLock::release_read()
{
#if CLICK_LINUXMODULE && defined(CONFIG_SMP)
_l[click_current_processor()]._lock.release();
click_put_processor();
#endif
}
/** @brief Acquires the ReadWriteLock for writing.
*
* On return, this thread has acquired the lock for writing. The function
* will spin indefinitely until the lock is acquired. It is OK to acquire a
* lock you have already acquired, but you must release it as many times as
* you have acquired it.
*
* @sa ReadWriteLock::acquire_read
*/
inline void
ReadWriteLock::acquire_write()
{
#if CLICK_LINUXMODULE && defined(CONFIG_SMP)
for (unsigned i = 0; i < (unsigned) num_possible_cpus(); i++)
_l[i]._lock.acquire();
#endif
}
/** @brief Attempts to acquire the ReadWriteLock for writing.
* @return True iff the ReadWriteLock was acquired.
*
* This function will acquire the lock for writing and return true only if the
* ReadWriteLock can be acquired right away, without retries. Note, however,
* that acquiring a ReadWriteLock requires as many operations as there are
* CPUs.
*
* @sa ReadWriteLock::attempt_read
*/
inline bool
ReadWriteLock::attempt_write()
{
#if CLICK_LINUXMODULE && defined(CONFIG_SMP)
bool all = true;
unsigned i;
for (i = 0; i < (unsigned) num_possible_cpus(); i++)
if (!(_l[i]._lock.attempt())) {
all = false;
break;
}
if (!all)
for (unsigned j = 0; j < i; j++)
_l[j]._lock.release();
return all;
#else
return true;
#endif
}
/** @brief Releases the ReadWriteLock for writing.
*
* The ReadWriteLock must have been previously acquired by either
* ReadWriteLock::acquire_write or ReadWriteLock::attempt_write. Do not call
* release_write() on a lock that was acquired for reading.
*
* @sa ReadWriteLock::release_read
*/
inline void
ReadWriteLock::release_write()
{
#if CLICK_LINUXMODULE && defined(CONFIG_SMP)
for (unsigned i = 0; i < (unsigned) num_possible_cpus(); i++)
_l[i]._lock.release();
#endif
}
CLICK_ENDDECLS
#undef SPINLOCK_ASSERTLEVEL
#endif

View File

@ -0,0 +1,648 @@
// -*- c-basic-offset: 4; related-file-name: "../../lib/task.cc" -*-
#ifndef CLICK_TASK_HH
#define CLICK_TASK_HH
#include <click/element.hh>
#include <click/sync.hh>
#if HAVE_MULTITHREAD
# include <click/atomic.hh>
# include <click/ewma.hh>
#endif
CLICK_DECLS
#if CLICK_BSDMODULE
# include <click/cxxprotect.h>
CLICK_CXX_PROTECT
# include <sys/lock.h>
# include <sys/mutex.h>
CLICK_CXX_UNPROTECT
# include <click/cxxunprotect.h>
#else
#define GIANT_REQUIRED
#endif
#define PASS_GT(a, b) ((int)(a - b) > 0)
typedef bool (*TaskCallback)(Task *, void *);
typedef TaskCallback TaskHook CLICK_DEPRECATED;
class RouterThread;
class TaskList;
class Master;
struct TaskLink {
#if !HAVE_TASK_HEAP
TaskLink *_prev;
TaskLink *_next;
#endif
#if HAVE_STRIDE_SCHED
unsigned _pass;
#endif
TaskLink() {
#if !HAVE_TASK_HEAP
_prev = _next = 0;
#endif
#if HAVE_STRIDE_SCHED
_pass = 0;
#endif
}
};
class Task : private TaskLink { public:
#if HAVE_STRIDE_SCHED
enum { STRIDE1 = 1U<<16, MAX_STRIDE = 1U<<31 };
enum { MAX_TICKETS = 1<<15, DEFAULT_TICKETS = 1<<10 };
#endif
#if HAVE_ADAPTIVE_SCHEDULER
enum { MAX_UTILIZATION = 1000 };
#endif
/** @brief Construct a task that calls @a f with @a user_data argument.
*
* @param f callback function
* @param user_data argument for callback function
*
* Constructs a task that, when fired, calls @a f like so:
*
* @code
* bool work_done = f(task, user_data);
* @endcode
*
* where @a task is a pointer to this task. @a f should return true if
* the task accomplished some meaningful work, and false if it did not.
* For example, a task that polls a network driver for packets should
* return true if it emits at least one packet, and false if no packets
* were available. */
inline Task(TaskCallback f, void *user_data);
/** @brief Construct a task that calls @a e ->@link Element::run_task(Task*) run_task()@endlink.
*
* @param e element to call
*
* Constructs a task that, when fired, calls the element @a e's @link
* Element::run_task(Task *) run_task()@endlink method, passing this Task
* as an argument.
*
* @sa Task(TaskCallback, void *) */
inline Task(Element *e);
/** @brief Destroy a task.
*
* Unschedules the task if necessary. */
~Task();
/** @brief Return the task's callback function.
*
* Returns null if the task was constructed with the Task(Element *)
* constructor. */
inline TaskCallback callback() const {
return _hook;
}
/** @brief Return the task callback function's user data. */
inline void *user_data() const {
return _thunk;
}
/** @brief Return the task's owning element. */
inline Element *element() const {
return _owner;
}
/** @brief Return true iff the task has been initialize()d. */
inline bool initialized() const;
/** @brief Return the task's home thread ID.
*
* This is the @link RouterThread::thread_id() thread_id()@endlink of the
* thread on which this Task would run if it were scheduled. This need
* not equal the ID of the current thread(), since changes in
* home_thread_id() aren't always implemented immediately (because of
* locking issues). */
inline int home_thread_id() const;
/** @brief Return the thread on which this task is currently scheduled,
* or would be scheduled.
*
* Usually, task->thread()->@link RouterThread::thread_id()
* thread_id()@endlink == task->home_thread_id(). They can differ,
* however, if move_thread() was called but the task hasn't yet been moved
* to the new thread. */
inline RouterThread *thread() const;
/** @brief Return the router to which this task belongs. */
inline Router *router() const {
return _owner->router();
}
/** @brief Return the master where this task will be scheduled. */
Master *master() const;
/** @brief Initialize the Task, and optionally schedule it.
* @param owner specifies the element owning the Task
* @param schedule if true, the Task will be scheduled immediately
*
* This function must be called on every Task before it is used. The
* corresponding router's ThreadSched, if any, is used to determine the
* task's initial thread assignment. The task initially has the default
* number of tickets, and is scheduled iff @a schedule is true.
*
* An assertion will fail if a Task is initialized twice.
*
* Most elements call ScheduleInfo::initialize_task() to initialize a Task
* object. The ScheduleInfo method additionally sets the task's
* scheduling parameters, such as ticket count and thread preference,
* based on a router's ScheduleInfo. ScheduleInfo::initialize_task()
* calls Task::initialize(). */
void initialize(Element *owner, bool schedule);
/** @brief Initialize the Task, and optionally schedule it.
* @param router specifies the router owning the Task
* @param schedule if true, the Task will be scheduled immediately
*
* This function is shorthand for @link Task::initialize(Element *, bool)
* Task::initialize@endlink(@a router ->@link Router::root_element
* root_element@endlink(), @a scheduled). However, it is better to
* explicitly associate tasks with real elements. */
void initialize(Router *router, bool schedule);
/** @brief Return true iff the task is currently scheduled to run.
*
* @note A scheduled task will usually run very soon, but not
* always; due to locking issues, the effects of some reschedule()
* requests may be delayed. Although a task unscheduled with
* strong_unschedule() may appear scheduled(), it will not run
* until strong_reschedule() is called. */
inline bool scheduled() const {
return _status.is_scheduled;
}
/** @brief Unschedule the task.
*
* After unschedule() returns, the task will not run until it is
* rescheduled with reschedule().
*
* @sa reschedule, strong_unschedule */
inline void unschedule() {
_status.is_scheduled = false;
}
/** @brief Reschedule the task.
*
* The task is rescheduled on its home thread. It will eventually run,
* unless its home thread is quiescent or it has been
* strong_unschedule()d.
*
* @sa unschedule, strong_reschedule */
inline void reschedule() {
_status.is_scheduled = true;
click_fence();
if (_pending_nextptr.x < 2)
complete_schedule(0);
}
/** @brief Reschedule a task from the task's callback function.
*
* @warning Only call @a task.fast_reschedule() while @a task is being
* fired, i.e., in its callback function. It is an error to call
* @task.fast_reschedule() at other times -- the task may not actually be
* rescheduled.
*
* Here's a typical, correct use of fast_reschedule():
*
* @code
* class MyElement : public Element {
* ... Task _task; ... bool run_task(Task *t); ...
* };
* bool MyElement::run_task(Task *) {
* do_some_work();
* _task.fast_reschedule();
* return true;
* }
* @endcode
*
* This assumes, however, that run_task() is only called directly by the
* driver. If you call run_task() from another context, _task may not
* actually be scheduled.
*
* @code
* void MyElement::run_timer(Timer *) {
* run_task(); // XXX might not reschedule _task!
* }
* @endcode
*/
inline void fast_reschedule() {
_status.is_scheduled = true;
}
/** @brief Unschedule the Task until strong_reschedule().
*
* Like unschedule(), but in addition, future reschedule() calls
* will not actually schedule the task. Only after strong_reschedule()
* will the task run again.
* @sa strong_reschedule, unschedule
*/
inline void strong_unschedule() {
_status.is_scheduled = false;
_status.is_strong_unscheduled = true;
}
/** @brief Reschedule the Task, undoing a prior strong_unschedule().
*
* This function undoes any previous strong_unschedule() and
* reschedules the task.
* @sa reschedule, strong_unschedule
*/
inline void strong_reschedule() {
_status.is_strong_unscheduled = false;
reschedule();
}
/** @brief Move the Task to a new home thread.
*
* The home thread ID is set to @a new_thread_id. The task, if it is
* currently scheduled, is rescheduled on thread @a new_thread_id
* (which generally takes some time to take effect). If @a new_thread_id
* is less than zero or greater than the number of threads on the router,
* the task is scheduled on a quiescent thread that never actually runs.
*/
void move_thread(int new_thread_id);
#if HAVE_STRIDE_SCHED
inline int tickets() const;
inline void set_tickets(int n);
inline void adjust_tickets(int delta);
#endif
inline bool fire();
#if HAVE_ADAPTIVE_SCHEDULER
inline unsigned runs() const;
inline unsigned work_done() const;
inline unsigned utilization() const;
inline void clear_runs();
#endif
#if HAVE_MULTITHREAD
inline int cycles() const;
inline unsigned cycle_runs() const;
inline void update_cycles(unsigned c);
#endif
/** @cond never */
inline TaskCallback hook() const CLICK_DEPRECATED;
inline void *thunk() const CLICK_DEPRECATED;
/** @endcond never */
private:
#if HAVE_TASK_HEAP
int _schedpos;
#endif
#if HAVE_STRIDE_SCHED
unsigned _stride;
int _tickets;
#endif
union Status {
struct {
int16_t home_thread_id;
uint8_t is_scheduled;
uint8_t is_strong_unscheduled;
};
uint32_t status;
} _status;
TaskCallback _hook;
void *_thunk;
#if HAVE_ADAPTIVE_SCHEDULER
unsigned _runs;
unsigned _work_done;
#endif
#if HAVE_MULTITHREAD
DirectEWMA _cycles;
unsigned _cycle_runs;
#endif
RouterThread *_thread;
Element *_owner;
union Pending {
Task *t;
uintptr_t x;
};
Pending _pending_nextptr;
Task(const Task &x);
Task &operator=(const Task &x);
void cleanup();
#if CLICK_DEBUG_SCHEDULING
public:
#endif
inline bool on_scheduled_list() const;
inline bool on_pending_list() const {
return _pending_nextptr.x != 0;
}
inline bool needs_cleanup() const;
#if CLICK_DEBUG_SCHEDULING
private:
#endif
void add_pending(bool always);
void process_pending(RouterThread* thread);
void complete_schedule(RouterThread* process_pending_thread);
inline void remove_from_scheduled_list();
static bool error_hook(Task *task, void *user_data);
friend class RouterThread;
friend class Master;
};
// need RouterThread's definition for inline functions
CLICK_ENDDECLS
#include <click/routerthread.hh>
CLICK_DECLS
inline
Task::Task(TaskCallback f, void *user_data)
:
#if HAVE_TASK_HEAP
_schedpos(-1),
#endif
#if HAVE_STRIDE_SCHED
_stride(0), _tickets(-1),
#endif
_hook(f), _thunk(user_data),
#if HAVE_ADAPTIVE_SCHEDULER
_runs(0), _work_done(0),
#endif
#if HAVE_MULTITHREAD
_cycle_runs(0),
#endif
_thread(0), _owner(0)
{
_status.home_thread_id = -2;
_status.is_scheduled = _status.is_strong_unscheduled = false;
_pending_nextptr.x = 0;
}
inline
Task::Task(Element* e)
:
#if HAVE_TASK_HEAP
_schedpos(-1),
#endif
#if HAVE_STRIDE_SCHED
_stride(0), _tickets(-1),
#endif
_hook(0), _thunk(e),
#if HAVE_ADAPTIVE_SCHEDULER
_runs(0), _work_done(0),
#endif
#if HAVE_MULTITHREAD
_cycle_runs(0),
#endif
_thread(0), _owner(0)
{
_status.home_thread_id = -2;
_status.is_scheduled = _status.is_strong_unscheduled = false;
_pending_nextptr.x = 0;
}
inline bool
Task::initialized() const
{
return _owner != 0;
}
inline bool
Task::on_scheduled_list() const
{
#if HAVE_TASK_HEAP
return _schedpos >= 0;
#else
return _prev != 0;
#endif
}
inline bool
Task::needs_cleanup() const
{
#if HAVE_TASK_HEAP
int a;
uintptr_t b;
do {
a = _schedpos;
b = _pending_nextptr.x;
click_fence();
} while (a != _schedpos || b != _pending_nextptr.x);
return a >= 0 || b != 0;
#else
TaskLink* a;
uintptr_t b;
do {
a = _prev;
b = _pending_nextptr.x;
click_fence();
} while (a != _prev || b != _pending_nextptr.x);
return a != 0 || b != 0;
#endif
}
/** @cond never */
/** @brief Return the task's callback function.
* @deprecated Use callback() instead. */
inline TaskCallback
Task::hook() const
{
return _hook;
}
/** @brief Return the task's callback data.
* @deprecated Use user_data() instead. */
inline void *
Task::thunk() const
{
return _thunk;
}
/** @endcond never */
inline int
Task::home_thread_id() const
{
return _status.home_thread_id;
}
inline RouterThread *
Task::thread() const
{
return _thread;
}
inline void
Task::remove_from_scheduled_list()
{
if (on_scheduled_list()) {
#if HAVE_TASK_HEAP
Task *back = _thread->_task_heap.back().t;
_thread->_task_heap.pop_back();
if (_thread->_task_heap.size() > 0)
_thread->task_reheapify_from(_schedpos, back);
click_fence();
_schedpos = -1;
#else
_next->_prev = _prev;
_prev->_next = _next;
_next = 0;
click_fence();
_prev = 0;
#endif
}
}
#if HAVE_STRIDE_SCHED
/** @brief Return the task's number of tickets.
*
* Tasks with larger numbers of tickets are scheduled more often. Tasks are
* initialized with tickets() == DEFAULT_TICKETS.
*
* @sa set_tickets, adjust_tickets
*/
inline int
Task::tickets() const
{
return _tickets;
}
/** @brief Set the task's ticket count.
* @param n the ticket count
*
* The ticket count @a n is pinned to the range [1, MAX_TICKETS].
*
* @sa tickets, adjust_tickets
*/
inline void
Task::set_tickets(int n)
{
if (n > MAX_TICKETS)
n = MAX_TICKETS;
else if (n < 1)
n = 1;
_tickets = n;
_stride = STRIDE1 / n;
assert(_stride < MAX_STRIDE);
}
/** @brief Add @a delta to the Task's ticket count.
* @param delta adjustment to the ticket count
*
* The ticket count cannot be adjusted below 1 or above MAX_TICKETS.
*
* @sa set_tickets
*/
inline void
Task::adjust_tickets(int delta)
{
set_tickets(_tickets + delta);
}
#endif /* HAVE_STRIDE_SCHED */
/** @brief Fire the task by calling its callback function.
*
* This function is generally called by the RouterThread implementation; there
* should be no need to call it yourself.
*/
inline bool
Task::fire()
{
#if CLICK_STATS >= 2
click_cycles_t start_cycles = click_get_cycles(),
start_child_cycles = _owner->_child_cycles;
#endif
#if HAVE_MULTITHREAD
_cycle_runs++;
#endif
bool work_done;
if (!_hook)
work_done = ((Element*)_thunk)->run_task(this);
else
work_done = _hook(this, _thunk);
#if HAVE_ADAPTIVE_SCHEDULER
++_runs;
_work_done += work_done;
#endif
#if CLICK_STATS >= 2
click_cycles_t all_delta = click_get_cycles() - start_cycles,
own_delta = all_delta - (_owner->_child_cycles - start_child_cycles);
_owner->_task_calls += 1;
_owner->_task_own_cycles += own_delta;
#endif
return work_done;
}
#if HAVE_ADAPTIVE_SCHEDULER
inline unsigned
Task::runs() const
{
return _runs;
}
inline unsigned
Task::work_done() const
{
return _work_done;
}
inline unsigned
Task::utilization() const
{
return (_runs ? (MAX_UTILIZATION * _work_done) / _runs : 0);
}
inline void
Task::clear_runs()
{
_runs = _work_done = 0;
}
#endif
#if HAVE_MULTITHREAD
inline int
Task::cycles() const
{
return _cycles.unscaled_average();
}
inline unsigned
Task::cycle_runs() const
{
return _cycle_runs;
}
inline void
Task::update_cycles(unsigned c)
{
_cycles.update(c);
_cycle_runs = 0;
}
#endif
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,397 @@
// -*- c-basic-offset: 4; related-file-name: "../../lib/timer.cc" -*-
#ifndef CLICK_TIMER_HH
#define CLICK_TIMER_HH
#include <click/sync.hh>
#include <click/glue.hh>
#include <click/element.hh>
#include <click/timestamp.hh>
CLICK_DECLS
class RouterThread;
typedef void (*TimerCallback)(Timer *timer, void *user_data);
typedef TimerCallback TimerHook CLICK_DEPRECATED;
class Timer { public:
/** @brief Construct a Timer that does nothing when fired.
*
* This constructor is most useful for a Timer that will be assigned a
* true callback later, using one of the Timer::assign() methods.
* Timer::initialize() will report a warning if called on a Timer created
* by this constructor. */
Timer();
struct do_nothing_t {
};
/** @brief Construct a Timer that does nothing when fired.
*
* Unlike with the default Timer() constructor, Timer::initialize() will
* not report a warning if called on a Timer created by this
* constructor. */
Timer(const do_nothing_t &unused);
/** @brief Construct a Timer that calls @a f(this, @a user_data) when
* fired.
* @param f callback function
* @param user_data argument for callback function */
Timer(TimerCallback f, void *user_data);
/** @brief Construct a Timer that calls @a element ->@link
* Element::run_timer() run_timer@endlink(this) when fired.
* @param element the element */
Timer(Element *element);
/** @brief Construct a Timer that schedules @a task when fired.
* @param task the task */
Timer(Task *task);
/** @brief Construct a Timer that acts like @a x when fired.
*
* The newly-constructed Timer is not initialized. */
Timer(const Timer &x);
/** @brief Destroy a Timer, unscheduling it first if necessary. */
inline ~Timer() {
if (scheduled())
unschedule();
}
/** @brief Change the Timer to do nothing when fired. */
inline void assign() {
_hook.callback = do_nothing_hook;
_thunk = (void *) 1;
}
/** @brief Change the Timer to do nothing when fired. */
inline void assign(const do_nothing_t &unused) {
(void) unused;
assign();
}
/** @brief Change the Timer to call @a f(this, @a user_data) when fired.
* @param f callback function
* @param user_data argument for callback function */
inline void assign(TimerCallback f, void *user_data) {
_hook.callback = f;
_thunk = user_data;
}
/** @brief Change the Timer to call @a element ->@link
* Element::run_timer() run_timer@endlink(this) when fired.
* @param element the element */
void assign(Element *element) {
_hook.callback = element_hook;
_thunk = element;
}
/** @brief Change the Timer to schedule @a task when fired.
* @param task the task */
void assign(Task *task) {
_hook.callback = task_hook;
_thunk = task;
}
/** @brief Return true iff the Timer has been initialized. */
inline bool initialized() const {
return _owner != 0;
}
/** @brief Return true iff the Timer is currently scheduled. */
inline bool scheduled() const {
return _schedpos1 != 0;
}
/** @brief Return the Timer's steady-clock expiration time.
*
* This is the absolute time, according to the steady clock, at which the
* timer is next scheduled to fire. If the timer is not currently
* scheduled, then expiry_steady() returns the last assigned expiration
* time.
*
* @sa expiry() */
inline const Timestamp &expiry_steady() const {
return _expiry_s;
}
/** @brief Return the Timer's system-clock expiration time.
*
* Timer expirations are measured using the system's steady clock, which
* increases monotonically. (See Timestamp::now_steady().) The expiry()
* function, however, returns the timer's expiration time according to the
* system clock. This is a calculated value: if the system clock changes
* -- because the user changes the current system time, for example --
* then the timer's expiry() will also change. (The timer's
* expiry_steady() value will not change, however.)
*
* @sa expiry_steady() */
inline Timestamp expiry() const {
if (_expiry_s)
return _expiry_s + Timestamp::recent() - Timestamp::recent_steady();
else
return _expiry_s;
}
/** @brief Return the Timer's associated Router. */
inline Router *router() const {
return _owner->router();
}
/** @brief Return the Timer's owning element. */
inline Element *element() const {
return _owner;
}
/** @brief Return the Timer's associated RouterThread. */
inline RouterThread *thread() const {
return _thread;
}
/** @brief Return the Timer's associated home thread ID. */
int home_thread_id() const;
/** @brief Initialize the timer.
* @param owner the owner element
* @param quiet do not produce default-constructor warning if true
*
* Before a timer can be used, it must be attached to a containing router.
* When that router is destroyed, the timer is automatically
* unscheduled. It is safe to initialize the timer multiple times
* on the same router.
*
* If Click is compiled with statistics support, time spent in this
* Timer will be charged to the @a owner element.
*
* Initializing a Timer constructed by the default constructor, Timer(),
* will produce a warning. */
void initialize(Element *owner, bool quiet = false);
/** @brief Initialize the timer.
* @param router the owner router
*
* This function is shorthand for @link
* Timer::initialize(Element*,bool) Timer::initialize@endlink(@a
* router ->@link Router::root_element root_element@endlink()).
* However, it is better to explicitly associate timers with real
* elements. */
void initialize(Router *router);
/** @brief Schedule the timer to fire at @a when_steady.
* @param when_steady expiration time according to the steady clock
*
* If @a when_steady is more than 2 seconds behind the current time, then
* the expiration time is silently updated to the current time.
*
* @sa schedule_at() */
void schedule_at_steady(const Timestamp &when_steady);
/** @brief Schedule the timer to fire at @a when_steady.
* @param when_steady expiration time according to the steady clock
*
* This is a synonym for schedule_at_steady(). */
void reschedule_at_steady(const Timestamp &when_steady);
/** @brief Schedule the timer to fire at @a when.
* @param when expiration time according to the system clock
*
* If @a when is more than 2 seconds behind system time, then the
* expiration time is silently updated to the current system time.
*
* @note The schedule_at_steady() function should generally be preferred
* to schedule_at(). schedule_at() is implemented in terms of
* schedule_at_steady().
*
* @sa schedule_at_steady() */
inline void schedule_at(const Timestamp &when);
/** @brief Schedule the timer to fire at @a when.
* @param when expiration time
*
* This is a synonym for schedule_at(). */
inline void reschedule_at(const Timestamp &when);
/** @brief Shedule the timer to fire immediately.
*
* Equivalent to schedule_at(Timestamp::recent()). */
inline void schedule_now() {
schedule_at_steady(Timestamp::recent_steady());
}
/** @brief Schedule the timer to fire @a delta time in the future.
* @param delta interval until expiration time
*
* The schedule_after methods schedule the timer relative to the current
* time. When called from a timer's callback function, this will usually
* be slightly after the timer's nominal expiration time. To schedule a
* timer at a strict interval, compensating for small amounts of drift,
* use the reschedule_after methods. */
void schedule_after(const Timestamp &delta);
/** @brief Schedule the timer to fire after @a delta_sec seconds.
* @param delta_sec interval until expiration time, in seconds
*
* @sa schedule_after, reschedule_after_sec */
inline void schedule_after_sec(uint32_t delta_sec) {
schedule_after(Timestamp(delta_sec, 0));
}
/** @brief Schedule the timer to fire after @a delta_msec milliseconds.
* @param delta_msec interval until expiration time, in milliseconds
*
* @sa schedule_after, reschedule_after_msec */
inline void schedule_after_msec(uint32_t delta_msec) {
schedule_after(Timestamp::make_msec(delta_msec));
}
/** @brief Schedule the timer to fire @a delta time after its previous
* expiry.
* @param delta interval until expiration time
*
* If the expiration time is too far in the past, then the new expiration
* time will be silently updated to the current system time.
*
* @sa schedule_after */
inline void reschedule_after(const Timestamp &delta) {
schedule_at_steady(_expiry_s + delta);
}
/** @brief Schedule the timer to fire @a delta_sec seconds after its
* previous expiry.
* @param delta_sec interval until expiration time, in seconds
*
* @sa schedule_after_sec, reschedule_after */
inline void reschedule_after_sec(uint32_t delta_sec) {
schedule_at_steady(Timestamp(_expiry_s.sec() + delta_sec, _expiry_s.subsec()));
}
/** @brief Schedule the timer to fire @a delta_msec milliseconds after its
* previous expiry.
* @param delta_msec interval until expiration time, in milliseconds
*
* @sa schedule_after_msec, reschedule_after */
inline void reschedule_after_msec(uint32_t delta_msec) {
schedule_at_steady(_expiry_s + Timestamp::make_msec(delta_msec));
}
/** @brief Unschedule the timer.
*
* The timer's expiration time is not modified. */
void unschedule();
/** @brief Unschedule the timer and reset its expiration time. */
inline void clear() {
unschedule();
_expiry_s = Timestamp();
}
/** @brief Return an adjustment interval useful for precise timers.
*
* Due to scheduling granularity, other tasks running on the same machine,
* and similar effects, a Timer object can trigger some time after its
* nominal expiry(). Functions that require precise timers should combine
* a Timer and a Task object. The Timer's job is to schedule the Task;
* the Timer's expiry is set to go off a short interval before the true
* expiry, and the Task is used to busy-wait the difference.
* Timer::adjustment() is an appropriate value for this time
* difference. */
static inline Timestamp adjustment() {
#if TIMESTAMP_WARPABLE
if (Timestamp::warp_jumping())
return Timestamp();
#endif
return Timestamp::make_usec(500);
}
/** @brief Schedule the timer to fire after @a delta_sec seconds
* (deprecated).
*
* @deprecated Use schedule_after_sec() instead. */
inline void schedule_after_s(uint32_t delta_sec) CLICK_DEPRECATED;
/** @brief Schedule the timer to fire after @a delta_msec milliseconds
* (deprecated).
*
* @deprecated Use schedule_after_msec() instead. */
inline void schedule_after_ms(uint32_t delta_sec) CLICK_DEPRECATED;
/** @brief Schedule the timer to fire @a delta_sec seconds after its
* previous expiry time (deprecated).
*
* @deprecated Use reschedule_after_sec() instead. */
inline void reschedule_after_s(uint32_t delta_sec) CLICK_DEPRECATED;
/** @brief Schedule the timer to fire @a delta_msec milliseconds after its
* previous expiry time (deprecated).
*
* @deprecated Use reschedule_after_msec() instead. */
inline void reschedule_after_ms(uint32_t delta_sec) CLICK_DEPRECATED;
enum { behind_sec = 1 };
private:
int _schedpos1;
Timestamp _expiry_s;
union {
TimerCallback callback;
} _hook;
void *_thunk;
Element *_owner;
RouterThread *_thread;
Timer &operator=(const Timer &x);
static void do_nothing_hook(Timer *t, void *user_data);
static void element_hook(Timer *t, void *user_data);
static void task_hook(Timer *t, void *user_data);
friend class TimerSet;
};
inline void
Timer::schedule_at(const Timestamp &when)
{
schedule_at_steady(when + Timestamp::recent_steady() - Timestamp::recent());
}
inline void
Timer::reschedule_at(const Timestamp &when)
{
schedule_at(when);
}
inline void
Timer::schedule_after_s(uint32_t delta_sec)
{
schedule_after_sec(delta_sec);
}
inline void
Timer::schedule_after_ms(uint32_t delta_msec)
{
schedule_after_msec(delta_msec);
}
inline void
Timer::reschedule_after_s(uint32_t delta_sec)
{
reschedule_after_sec(delta_sec);
}
inline void
Timer::reschedule_after_ms(uint32_t delta_msec)
{
reschedule_after_msec(delta_msec);
}
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,162 @@
// -*- related-file-name: "../../lib/timerset.cc" -*-
#ifndef CLICK_TIMERSET_HH
#define CLICK_TIMERSET_HH 1
#include <click/timer.hh>
#include <click/sync.hh>
#include <click/vector.hh>
CLICK_DECLS
class Router;
class RouterThread;
class Timer;
class TimerSet { public:
TimerSet();
Timestamp timer_expiry_steady() const { return _timer_expiry; }
inline Timestamp timer_expiry_steady_adjusted() const;
#if CLICK_USERLEVEL
inline int next_timer_delay(bool more_tasks, Timestamp &t) const;
#endif
Timer *next_timer(); // useful for benchmarking
unsigned max_timer_stride() const { return _max_timer_stride; }
unsigned timer_stride() const { return _timer_stride; }
void set_max_timer_stride(unsigned timer_stride);
void kill_router(Router *router);
void run_timers(RouterThread *thread, Master *master);
inline void fence();
private:
struct heap_element {
Timestamp expiry_s;
Timer *t;
#if SIZEOF_VOID_P == 4
uint32_t padding; /* the structure should have size 16 */
#endif
heap_element(Timer *t_)
: expiry_s(t_->expiry_steady()), t(t_) {
}
};
struct heap_less {
inline bool operator()(const heap_element &a, const heap_element &b) {
return a.expiry_s < b.expiry_s;
}
};
struct heap_place {
inline void operator()(heap_element *begin, heap_element *t) {
t->t->_schedpos1 = (t - begin) + 1;
}
};
// Most likely _timer_expiry now fits in a cache line
Timestamp _timer_expiry CLICK_ALIGNED(8);
unsigned _max_timer_stride;
unsigned _timer_stride;
unsigned _timer_count;
Vector<heap_element> _timer_heap;
Vector<Timer *> _timer_runchunk;
SimpleSpinlock _timer_lock;
#if CLICK_LINUXMODULE
struct task_struct *_timer_task;
#elif HAVE_MULTITHREAD
click_processor_t _timer_processor;
#endif
Timestamp _timer_check;
uint32_t _timer_check_reports;
inline void run_one_timer(Timer *);
void set_timer_expiry() {
if (_timer_heap.size())
_timer_expiry = _timer_heap.unchecked_at(0).expiry_s;
else
_timer_expiry = Timestamp();
}
void check_timer_expiry(Timer *t);
inline void lock_timers();
inline bool attempt_lock_timers();
inline void unlock_timers();
friend class Timer;
};
inline Timestamp
TimerSet::timer_expiry_steady_adjusted() const
{
Timestamp e = _timer_expiry;
#if TIMESTAMP_WARPABLE
if (likely(!Timestamp::warp_jumping())) {
#endif
if (_timer_stride >= 8 || !e)
/* do nothing */;
else if (_timer_stride >= 4)
e -= Timer::adjustment();
else
e -= Timer::adjustment() + Timer::adjustment();
#if TIMESTAMP_WARPABLE
}
#endif
return e;
}
inline void
TimerSet::lock_timers()
{
#if CLICK_LINUXMODULE
if (current != _timer_task)
_timer_lock.acquire();
#elif HAVE_MULTITHREAD
if (click_current_processor() != _timer_processor)
_timer_lock.acquire();
#endif
}
inline bool
TimerSet::attempt_lock_timers()
{
#if CLICK_LINUXMODULE || HAVE_MULTITHREAD
return _timer_lock.attempt();
#else
return true;
#endif
}
inline void
TimerSet::unlock_timers()
{
#if CLICK_LINUXMODULE
if (current != _timer_task)
_timer_lock.release();
#elif HAVE_MULTITHREAD
if (click_current_processor() != _timer_processor)
_timer_lock.release();
#endif
}
inline void
TimerSet::fence()
{
lock_timers();
unlock_timers();
}
inline Timer *
TimerSet::next_timer()
{
lock_timers();
Timer *t = _timer_heap.empty() ? 0 : _timer_heap.unchecked_at(0).t;
unlock_timers();
return t;
}
CLICK_ENDDECLS
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,522 @@
#ifndef CLICK_TYPE_TRAITS_HH
#define CLICK_TYPE_TRAITS_HH
CLICK_DECLS
/** @file <click/type_traits.hh>
@brief Type traits structures. */
/** @class integral_constant
@brief Type wrapper for an integral constant V.
Offers the following members:
<dl>
<dt>type</dt>
<dd>The type itself.</dd>
<dt>value_type</dt>
<dd>The type argument T.</dd>
<dt>value</dt>
<dd>The value argument V.</dd>
</dl> */
template <typename T, T V>
struct integral_constant {
typedef integral_constant<T, V> type;
typedef T value_type;
static constexpr T value = V;
};
template <typename T, T V> constexpr T integral_constant<T, V>::value;
/** @class true_type
@brief Type wrapper for the constant true. */
typedef integral_constant<bool, true> true_type;
/** @class false_type
@brief Type wrapper for the constant false. */
typedef integral_constant<bool, false> false_type;
/** @class conditional
@brief Conditional type transformation.
If B is true, then conditional<B, T, F>::type is equivalent to T.
Otherwise, it is equivalent to F. */
template <bool B, typename T, typename F> struct conditional {};
template <typename T, typename F>
struct conditional<true, T, F> {
typedef T type;
};
template <typename T, typename F>
struct conditional<false, T, F> {
typedef F type;
};
/** @class has_trivial_copy
@brief Template determining whether T may be copied by memcpy.
has_trivial_copy<T> is equivalent to true_type if T has a trivial
copy constructor, false_type if it does not. */
#if HAVE___HAS_TRIVIAL_COPY
template <typename T> struct has_trivial_copy : public integral_constant<bool, __has_trivial_copy(T)> {};
#else
template <typename T> struct has_trivial_copy : public false_type {};
template <> struct has_trivial_copy<unsigned char> : public true_type {};
template <> struct has_trivial_copy<signed char> : public true_type {};
template <> struct has_trivial_copy<char> : public true_type {};
template <> struct has_trivial_copy<unsigned short> : public true_type {};
template <> struct has_trivial_copy<short> : public true_type {};
template <> struct has_trivial_copy<unsigned> : public true_type {};
template <> struct has_trivial_copy<int> : public true_type {};
template <> struct has_trivial_copy<unsigned long> : public true_type {};
template <> struct has_trivial_copy<long> : public true_type {};
# if HAVE_LONG_LONG
template <> struct has_trivial_copy<unsigned long long> : public true_type {};
template <> struct has_trivial_copy<long long> : public true_type {};
# endif
template <typename T> struct has_trivial_copy<T*> : public true_type {};
#endif
class IPAddress;
template <> struct has_trivial_copy<IPAddress> : public true_type {};
/** @class is_reference
@brief Template determining whether T is a reference type.
is_reference<T> is equivalent to true_type if T is a reference type (T& or
T&&), false_type if it is not. */
template <typename T> struct is_reference : public false_type {};
template <typename T> struct is_reference<T&> : public true_type {};
#if HAVE_CXX_RVALUE_REFERENCES
template <typename T> struct is_reference<T&&> : public true_type {};
#endif
/** @class remove_reference
@brief Template removing any reference layer from T.
Assuming T is a non-reference type, then all of remove_reference<T>::type,
remove_reference<T&>::type, and remove_reference<T&&>::type are equivalent
to T. */
template <typename T> struct remove_reference {
typedef T type;
};
template <typename T> struct remove_reference<T&> {
typedef T type;
};
#if HAVE_CXX_RVALUE_REFERENCES
template <typename T> struct remove_reference<T&&> {
typedef T type;
};
template <typename T>
inline typename remove_reference<T>::type&& click_move(T&& x) {
return static_cast<typename remove_reference<T>::type&&>(x);
}
#endif
template <typename T> struct remove_cv {
typedef T type;
};
template <typename T> struct remove_cv<const T> {
typedef T type;
};
template <typename T> struct remove_cv<volatile T> {
typedef T type;
};
template <typename T> struct remove_cv<const volatile T> {
typedef T type;
};
template <typename T, typename U> struct same_type : public false_type {};
template <typename T> struct same_type<T, T> : public true_type {};
template <typename T, typename U> struct types_compatible
: public same_type<typename remove_cv<T>::type, typename remove_cv<U>::type> {};
/** @class fast_argument
@brief Template defining a fast argument type for objects of type T.
fast_argument<T>::type equals either "const T &" or "T".
fast_argument<T>::is_reference is true iff fast_argument<T>::type is
a reference. If fast_argument<T>::is_reference is true, then
fast_argument<T>::enable_rvalue_reference is a typedef to void; otherwise
it is not defined. */
template <typename T, bool use_reference = (!is_reference<T>::value
&& (!has_trivial_copy<T>::value
|| sizeof(T) > sizeof(void *)))>
struct fast_argument;
template <typename T> struct fast_argument<T, true> {
static constexpr bool is_reference = true;
typedef const T &type;
#if HAVE_CXX_RVALUE_REFERENCES
typedef void enable_rvalue_reference;
#endif
};
template <typename T> struct fast_argument<T, false> {
static constexpr bool is_reference = false;
typedef T type;
};
template <typename T> constexpr bool fast_argument<T, true>::is_reference;
template <typename T> constexpr bool fast_argument<T, false>::is_reference;
/** @class char_array
@brief Template defining a fixed-size character array. */
template <size_t S> struct char_array {
char x[S];
} CLICK_SIZE_PACKED_ATTRIBUTE;
template <size_t S> struct has_trivial_copy<char_array<S> > : public true_type {};
#if HAVE_INT64_TYPES && (!HAVE_LONG_LONG || SIZEOF_LONG_LONG < 8)
typedef int64_t click_intmax_t;
typedef uint64_t click_uintmax_t;
# define SIZEOF_CLICK_INTMAX_T 8
# define CLICK_ERRHdMAX "^64d"
# define CLICK_ERRHuMAX "^64u"
# define CLICK_ERRHoMAX "^64o"
# define CLICK_ERRHxMAX "^64x"
# define CLICK_ERRHXMAX "^64X"
#elif HAVE_LONG_LONG
typedef long long click_intmax_t;
typedef unsigned long long click_uintmax_t;
# define SIZEOF_CLICK_INTMAX_T SIZEOF_LONG_LONG
# define CLICK_ERRHdMAX "lld"
# define CLICK_ERRHuMAX "llu"
# define CLICK_ERRHoMAX "llo"
# define CLICK_ERRHxMAX "llx"
# define CLICK_ERRHXMAX "llX"
#else
typedef long click_intmax_t;
typedef unsigned long click_uintmax_t;
# define SIZEOF_CLICK_INTMAX_T SIZEOF_LONG
# define CLICK_ERRHdMAX "ld"
# define CLICK_ERRHuMAX "lu"
# define CLICK_ERRHoMAX "lo"
# define CLICK_ERRHxMAX "lx"
# define CLICK_ERRHXMAX "lX"
#endif
typedef click_intmax_t click_int_large_t;
typedef click_uintmax_t click_uint_large_t;
#define SIZEOF_CLICK_INT_LARGE_T SIZEOF_CLICK_INTMAX_T
#define CLICK_ERRHdLARGE CLICK_ERRHdMAX
#define CLICK_ERRHuLARGE CLICK_ERRHuMAX
#define CLICK_ERRHoLARGE CLICK_ERRHoMAX
#define CLICK_ERRHxLARGE CLICK_ERRHxMAX
#define CLICK_ERRHXLARGE CLICK_ERRHXMAX
/** @class integer_traits
@brief Numeric traits template.
The integer_traits template defines constants and type definitions related
to integers. Where T is an integer, integer_traits<T> defines:
<dl>
<dt>const T const_min</dt>
<dd>The minimum value defined for the type.</dd>
<dt>const T const_max</dt>
<dd>The maximum value available for the type.</dd>
<dt>const bool is_numeric</dt>
<dd>True.</dd>
<dt>const bool is_integral</dt>
<dd>True.</dd>
<dt>const bool is_signed</dt>
<dd>True iff the type is signed.</dd>
<dt>signed_type (typedef)</dt>
<dd>Signed version of the type.</dd>
<dt>unsigned_type (typedef)</dt>
<dd>Unsigned version of the type.</dd>
</dl>
If T is <em>not</em> an integer, integer_traits<T> defines:
<dl>
<dt>constexpr bool is_numeric</dt>
<dd>False.</dd>
<dt>constexpr bool is_integral</dt>
<dd>False.</dd>
</dl> */
template <typename T>
struct integer_traits {
static constexpr bool is_numeric = false;
static constexpr bool is_integral = false;
};
template <typename T> constexpr bool integer_traits<T>::is_numeric;
template <typename T> constexpr bool integer_traits<T>::is_integral;
template <>
struct integer_traits<unsigned char> {
static constexpr bool is_numeric = true;
static constexpr bool is_integral = true;
static constexpr unsigned char const_min = 0;
static constexpr unsigned char const_max = ~const_min;
static constexpr bool is_signed = false;
typedef signed char signed_type;
typedef unsigned char unsigned_type;
typedef unsigned char type;
typedef click_uintmax_t max_type;
static bool negative(type) { return false; }
};
template <>
struct integer_traits<signed char> {
static constexpr bool is_numeric = true;
static constexpr bool is_integral = true;
static constexpr signed char const_min = -128;
static constexpr signed char const_max = 127;
static constexpr bool is_signed = true;
typedef signed char signed_type;
typedef unsigned char unsigned_type;
typedef signed char type;
typedef click_intmax_t max_type;
static bool negative(type x) { return x < 0; }
};
#if __CHAR_UNSIGNED__
template <>
struct integer_traits<char> : public integer_traits<unsigned char> {
static constexpr char const_min = 0;
static constexpr char const_max = ~const_min;
typedef char type;
static bool negative(type) { return false; }
};
#else
template <>
struct integer_traits<char> : public integer_traits<signed char> {
static constexpr char const_min = -128;
static constexpr char const_max = 127;
typedef char type;
static bool negative(type x) { return x < 0; }
};
#endif
template <>
struct integer_traits<unsigned short> {
static constexpr bool is_numeric = true;
static constexpr bool is_integral = true;
static constexpr unsigned short const_min = 0;
static constexpr unsigned short const_max = ~const_min;
static constexpr bool is_signed = false;
typedef short signed_type;
typedef unsigned short unsigned_type;
typedef unsigned short type;
typedef click_uintmax_t max_type;
static bool negative(type) { return false; }
};
template <>
struct integer_traits<short> {
static constexpr bool is_numeric = true;
static constexpr bool is_integral = true;
static constexpr short const_min = -32768;
static constexpr short const_max = 32767;
static constexpr bool is_signed = true;
typedef short signed_type;
typedef unsigned short unsigned_type;
typedef short type;
typedef click_intmax_t max_type;
static bool negative(type x) { return x < 0; }
};
template <>
struct integer_traits<unsigned int> {
static constexpr bool is_numeric = true;
static constexpr bool is_integral = true;
static constexpr unsigned int const_min = 0;
static constexpr unsigned int const_max = ~const_min;
static constexpr bool is_signed = false;
typedef int signed_type;
typedef unsigned int unsigned_type;
typedef unsigned int type;
typedef click_uintmax_t max_type;
static bool negative(type) { return false; }
};
template <>
struct integer_traits<int> {
static constexpr bool is_numeric = true;
static constexpr bool is_integral = true;
static constexpr int const_min = 1 << (8*SIZEOF_INT - 1);
static constexpr int const_max = (unsigned) const_min - 1;
static constexpr bool is_signed = true;
typedef int signed_type;
typedef unsigned int unsigned_type;
typedef int type;
typedef click_intmax_t max_type;
static bool negative(type x) { return x < 0; }
};
template <>
struct integer_traits<unsigned long> {
static constexpr bool is_numeric = true;
static constexpr bool is_integral = true;
static constexpr unsigned long const_min = 0;
static constexpr unsigned long const_max = ~const_min;
static constexpr bool is_signed = false;
typedef long signed_type;
typedef unsigned long unsigned_type;
typedef unsigned long type;
typedef click_uintmax_t max_type;
static bool negative(type) { return false; }
};
template <>
struct integer_traits<long> {
static constexpr bool is_numeric = true;
static constexpr bool is_integral = true;
static constexpr long const_min = (long) 1 << (8*SIZEOF_LONG - 1);
static constexpr long const_max = (unsigned long) const_min - 1;
static constexpr bool is_signed = true;
typedef long signed_type;
typedef unsigned long unsigned_type;
typedef long type;
typedef click_intmax_t max_type;
static bool negative(type x) { return x < 0; }
};
#if HAVE_LONG_LONG
template <>
struct integer_traits<unsigned long long> {
static constexpr bool is_numeric = true;
static constexpr bool is_integral = true;
static constexpr unsigned long long const_min = 0;
static constexpr unsigned long long const_max = ~const_min;
static constexpr bool is_signed = false;
typedef long long signed_type;
typedef unsigned long long unsigned_type;
typedef unsigned long long type;
typedef click_uintmax_t max_type;
static bool negative(type) { return false; }
};
template <>
struct integer_traits<long long> {
static constexpr bool is_numeric = true;
static constexpr bool is_integral = true;
static constexpr long long const_min = (long long) 1 << (8*SIZEOF_LONG_LONG - 1);
static constexpr long long const_max = (unsigned long long) const_min - 1;
static constexpr bool is_signed = true;
typedef long long signed_type;
typedef unsigned long long unsigned_type;
typedef long long type;
typedef click_intmax_t max_type;
static bool negative(type x) { return x < 0; }
};
#endif
#if HAVE_INT64_TYPES && !HAVE_INT64_IS_LONG && !HAVE_INT64_IS_LONG_LONG
template <>
struct integer_traits<uint64_t> {
static constexpr bool is_numeric = true;
static constexpr bool is_integral = true;
static constexpr uint64_t const_min = 0;
static constexpr uint64_t const_max = ~const_min;
static constexpr bool is_signed = false;
typedef int64_t signed_type;
typedef uint64_t unsigned_type;
typedef uint64_t type;
typedef click_uintmax_t max_type;
static bool negative(type) { return false; }
};
template <>
struct integer_traits<int64_t> {
static constexpr bool is_numeric = true;
static constexpr bool is_integral = true;
static constexpr int64_t const_min = (int64_t) 1 << 63;
static constexpr int64_t const_max = (uint64_t) const_min - 1;
static constexpr bool is_signed = true;
typedef int64_t signed_type;
typedef uint64_t unsigned_type;
typedef int64_t type;
typedef click_intmax_t max_type;
static bool negative(type x) { return x < 0; }
};
#endif
/** @class make_signed
@brief Signed integer type transformation.
Given an integer type T, the type make_signed<T>::type is the signed version
of T.
@sa integer_traits */
template <typename T>
struct make_signed {
typedef typename integer_traits<T>::signed_type type;
};
/** @class make_unsigned
@brief Unsigned integer type transformation.
Given an integer type T, the type make_unsigned<T>::type is the unsigned
version of T.
@sa integer_traits */
template <typename T>
struct make_unsigned {
typedef typename integer_traits<T>::unsigned_type type;
};
/** @cond never */
template <typename T, typename Thalf>
struct make_fast_half_integer {
typedef T type;
typedef Thalf half_type;
static constexpr int half_bits = int(sizeof(type) * 4);
static constexpr type half_value = type(1) << half_bits;
static half_type low(type x) {
return x & (half_value - 1);
}
static half_type high(type x) {
return x >> (sizeof(type) * 4);
}
};
/** @endcond never */
/** @class fast_half_integer
@brief Type transformation for big integers. */
template <typename T> struct fast_half_integer : public make_fast_half_integer<T, T> {};
#if SIZEOF_LONG >= 8 && SIZEOF_LONG <= 2 * SIZEOF_INT
template <> struct fast_half_integer<unsigned long> : public make_fast_half_integer<unsigned long, unsigned int> {};
#endif
#if HAVE_LONG_LONG && SIZEOF_LONG_LONG <= 2 * SIZEOF_INT
template <> struct fast_half_integer<unsigned long long> : public make_fast_half_integer<unsigned long long, unsigned int> {};
#endif
#if HAVE_INT64_TYPES && !HAVE_INT64_IS_LONG_LONG && !HAVE_INT64_IS_LONG && SIZEOF_INT >= 4
template <> struct fast_half_integer<uint64_t> : public make_fast_half_integer<uint64_t, unsigned int> {};
#endif
template <int n, typename Limb, typename V>
struct extract_integer_helper {
static void extract(const Limb *x, V &value) {
extract_integer_helper<n - 1, Limb, V>::extract(x + 1, value);
value = (value << (sizeof(Limb) * 8)) | *x;
}
};
template <typename Limb, typename V>
struct extract_integer_helper<1, Limb, V> {
static void extract(const Limb *x, V &value) {
value = x[0];
}
};
/** @brief Extract an integral type from a multi-limb integer. */
template <typename Limb, typename V>
inline void extract_integer(const Limb *x, V &value) {
extract_integer_helper<
int((sizeof(V) + sizeof(Limb) - 1) / sizeof(Limb)), Limb, V
>::extract(x, value);
}
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,97 @@
// -*- c-basic-offset: 2; related-file-name: "../../lib/userutils.cc" -*-
#ifndef CLICK_USERUTILS_HH
#define CLICK_USERUTILS_HH
#include <click/archive.hh>
#include <stdio.h>
CLICK_DECLS
class ErrorHandler;
inline bool glob_match(const String &string, const String &pattern) {
return string.glob_match(pattern);
}
String percent_substitute(const String &string, int format1, ...);
/** @brief strcmp() replacement that compares numbers numerically.
* @return < 0 if @a a < @a b, > 0 if @a a > @a b, 0 if @a a == @a b
*
* Compares strings of digit characters like decimal numbers, and other
* characters using character-by-character comparison. For example:
* @code
* assert(click_strcmp("a", "b") < 0);
* assert(click_strcmp("a9", "a10") < 0);
* assert(click_strcmp("a001", "a2") < 0); // 1 < 2
* assert(click_strcmp("a001", "a1") > 0); // longer string of initial zeros
* @endcode
*
* Letters are compared first by lowercase. If two strings are identical
* except for case, then uppercase letters compare less than lowercase
* letters. For example:
* @code
* assert(click_strcmp("a", "B") < 0);
* assert(click_strcmp("Baa", "baa") < 0);
* assert(click_strcmp("Baa", "caa") < 0);
* assert(click_strcmp("baa", "Caa") < 0);
* @endcode
*
* Two strings compare as equal only if they are character-by-character
* equal. */
int click_strcmp(const String &a, const String &b);
/** @brief Portable replacement for sigaction().
* @param signum signal number
* @param handler signal action function
* @param resethand true if the handler should be reset when the signal is
* received, false otherwise
*
* Expands to either sigaction() or signal(). */
void click_signal(int signum, void (*handler)(int), bool resethand);
const char *filename_landmark(const char *, bool file_is_expr = false);
String file_string(FILE *, ErrorHandler * = 0);
String file_string(String, ErrorHandler * = 0);
String unique_tmpnam(const String &, ErrorHandler * = 0);
void remove_file_on_exit(const String &);
bool path_allows_default_path(String path);
String click_mktmpdir(ErrorHandler * = 0);
const char *clickpath();
void set_clickpath(const char *);
String clickpath_find_file(const String& filename, const char *subdir,
String default_path, ErrorHandler * = 0);
void clickpath_expand_path(const char* subdir, const String& default_path, Vector<String>&);
void parse_tabbed_lines(const String &, Vector<String> *, ...);
ArchiveElement init_archive_element(const String &, int);
String shell_quote(const String &, bool quote_tilde = false);
String shell_command_output_string(String command_line, const String &command_stdin, ErrorHandler *);
/** @brief Return true iff @a buf looks like it contains compressed data.
* @param buf buffer
* @param len number of characters in @a buf, should be >= 10
*
* Checks @a buf for signatures corresponding to zip, gzip, and bzip2
* compressed data, returning true iff a signature matches. @a len can be any
* number, but should be relatively large or compression might not be
* detected. Currently it must be at least 10 to detect bzip2 compression. */
bool compressed_data(const unsigned char *buf, int len);
FILE *open_uncompress_pipe(const String &filename, const unsigned char *buf,
int len, ErrorHandler *errh);
int compressed_filename(const String &filename);
FILE *open_compress_pipe(const String &filename, ErrorHandler *);
#if HAVE_DYNAMIC_LINKING
int clickdl_load_package(String, ErrorHandler *);
void clickdl_load_requirement(String, const Vector<ArchiveElement> *archive, ErrorHandler *);
#endif
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,50 @@
// -*- c-basic-offset: 4; related-file-name: "../../lib/variableenv.cc" -*-
#ifndef CLICK_VARIABLEENVIRONMENT_HH
#define CLICK_VARIABLEENVIRONMENT_HH
#include <click/string.hh>
#include <click/vector.hh>
CLICK_DECLS
class StringAccum;
class VariableExpander { public:
VariableExpander() { }
virtual ~VariableExpander() { }
virtual int expand(const String &var, String &expansion, int vartype, int depth) const = 0;
};
class VariableEnvironment : public VariableExpander { public:
VariableEnvironment(VariableEnvironment *parent);
int depth() const { return _depth; }
int size() const { return _names.size(); }
bool defines(const String &name) const;
const String &name(int i) const { return _names[i]; }
const Vector<String> &values() const { return _values; }
const String &value(int i) const { return _values[i]; }
const String &value(const String &name, bool &found) const;
void clear() { _names.clear(); _values.clear(); }
VariableEnvironment *parent_of(int depth) const;
bool define(const String &name, const String &value, bool override);
int expand(const String &var, String &expansion, int vartype, int depth) const;
private:
Vector<String> _names;
Vector<String> _values;
int _depth;
VariableEnvironment *_parent;
};
String cp_expand(const String &str, const VariableExpander &env,
bool expand_quote = false, int depth = 0);
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,165 @@
/*
* vector.{cc,hh} -- simple array template class
* Eddie Kohler
*
* Copyright (c) 1999-2000 Massachusetts Institute of Technology
* Copyright (c) 2006 Regents of the University of California
* Copyright (c) 2011 Eddie Kohler
*
* 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.
*/
#ifndef CLICK_VECTOR_CC
#define CLICK_VECTOR_CC
#include <click/glue.hh>
#include <click/vector.hh>
CLICK_DECLS
/** @cond never */
template <typename AM>
vector_memory<AM>::~vector_memory()
{
AM::destroy(l_, n_);
CLICK_LFREE(l_, capacity_ * sizeof(type));
}
template <typename AM>
void vector_memory<AM>::assign(const vector_memory<AM> &x)
{
if (&x != this) {
AM::destroy(l_, n_);
AM::mark_noaccess(l_, n_);
n_ = 0;
if (reserve_and_push_back(x.n_, 0)) {
n_ = x.n_;
AM::mark_undefined(l_, n_);
AM::copy(l_, x.l_, n_);
}
}
}
template <typename AM>
void vector_memory<AM>::assign(size_type n, const type *vp)
{
if (unlikely(need_argument_copy(vp))) {
type v_copy(*vp);
return assign(n, &v_copy);
}
resize(0, vp);
resize(n, vp);
}
template <typename AM>
typename vector_memory<AM>::iterator vector_memory<AM>::insert(iterator it, const type *vp)
{
assert(it >= begin() && it <= end());
if (unlikely(need_argument_copy(vp))) {
type v_copy(*vp);
return insert(it, &v_copy);
}
if (n_ == capacity_) {
size_type pos = it - begin();
if (!reserve_and_push_back(-1, 0))
return end();
it = begin() + pos;
}
AM::mark_undefined(l_ + n_, 1);
AM::move(it + 1, it, end() - it);
AM::mark_undefined(it, 1);
AM::fill(it, 1, vp);
++n_;
return it;
}
template <typename AM>
typename vector_memory<AM>::iterator vector_memory<AM>::erase(iterator a, iterator b)
{
if (a < b) {
assert(a >= begin() && b <= end());
AM::move_onto(a, b, end() - b);
n_ -= b - a;
AM::destroy(end(), b - a);
AM::mark_noaccess(end(), b - a);
return a;
} else
return b;
}
template <typename AM>
bool vector_memory<AM>::reserve_and_push_back(size_type want, const type *push_vp)
{
if (unlikely(push_vp && need_argument_copy(push_vp))) {
type push_v_copy(*push_vp);
return reserve_and_push_back(want, &push_v_copy);
}
if (want < 0)
want = (capacity_ > 0 ? capacity_ * 2 : 4);
if (want > capacity_) {
type *new_l = (type *) CLICK_LALLOC(want * sizeof(type));
if (!new_l)
return false;
AM::mark_noaccess(new_l + n_, want - n_);
AM::move(new_l, l_, n_);
CLICK_LFREE(l_, capacity_ * sizeof(type));
l_ = new_l;
capacity_ = want;
}
if (unlikely(push_vp))
push_back(push_vp);
return true;
}
template <typename AM>
void vector_memory<AM>::resize(size_type n, const type *vp)
{
if (unlikely(need_argument_copy(vp))) {
type v_copy(*vp);
return resize(n, &v_copy);
}
if (n <= capacity_ || reserve_and_push_back(n, 0)) {
assert(n >= 0);
if (n < n_) {
AM::destroy(l_ + n, n_ - n);
AM::mark_noaccess(l_ + n, n_ - n);
}
if (n_ < n) {
AM::mark_undefined(l_ + n_, n - n_);
AM::fill(l_ + n_, n - n_, vp);
}
n_ = n;
}
}
template <typename AM>
void vector_memory<AM>::swap(vector_memory<AM> &x)
{
type *l = l_;
l_ = x.l_;
x.l_ = l;
size_type n = n_;
n_ = x.n_;
x.n_ = n;
size_type capacity = capacity_;
capacity_ = x.capacity_;
x.capacity_ = capacity;
}
/** @endcond never */
CLICK_ENDDECLS
#endif

View File

@ -0,0 +1,518 @@
#ifndef CLICK_VECTOR_HH
#define CLICK_VECTOR_HH
#include <click/algorithm.hh>
#include <click/array_memory.hh>
CLICK_DECLS
/** @file <click/vector.hh>
@brief Click's vector container template. */
/** @cond never */
template <typename AM> class vector_memory { public:
typedef int size_type;
typedef typename AM::type type;
typedef type *iterator;
inline bool need_argument_copy(const type *argp) const {
return fast_argument<type>::is_reference
&& (uintptr_t) argp - (uintptr_t) l_ < (size_t) (n_ * sizeof(type));
}
vector_memory()
: l_(0), n_(0), capacity_(0) {
}
~vector_memory();
void assign(const vector_memory<AM> &x);
void assign(size_type n, const type *vp);
void resize(size_type n, const type *vp);
iterator begin() {
return l_;
}
iterator end() {
return l_ + n_;
}
iterator insert(iterator it, const type *vp);
iterator erase(iterator a, iterator b);
inline void push_back(const type *vp) {
if (n_ < capacity_) {
AM::mark_undefined(l_ + n_, 1);
AM::fill(l_ + n_, 1, vp);
++n_;
} else
reserve_and_push_back(-1, vp);
}
#if HAVE_CXX_RVALUE_REFERENCES
inline void move_construct_back(type* vp) {
if (n_ < capacity_) {
AM::mark_undefined(l_ + n_, 1);
AM::move_construct(l_ + n_, vp);
++n_;
} else
reserve_and_push_back(-1, vp);
}
#endif
inline void pop_back() {
assert(n_ > 0);
--n_;
AM::destroy(l_ + n_, 1);
AM::mark_noaccess(l_ + n_, 1);
}
inline void clear() {
AM::destroy(l_, n_);
AM::mark_noaccess(l_, n_);
n_ = 0;
}
bool reserve_and_push_back(size_type n, const type *vp);
void swap(vector_memory<AM> &x);
type *l_;
size_type n_;
size_type capacity_;
};
/** @endcond never */
/** @class Vector
@brief Vector template.
Vector implements a vector, or growable array, suitable for use in the
kernel or at user level. Its interface should be compatible with C++'s
std::vector, although that type has more methods. Vector elements are
accessed with operator[] like arrays, and can be resized and expanded
through append operations (see push_back() and resize()). A common (and
efficient) usage pattern grows a Vector through repeated push_back() calls.
Vector iterators are pointers into the underlying array. This can simplify
interactions between Vector and code that expects conventional C arrays.
Vector's push_front() and pop_front() operations are quite expensive (O(size())
complexity). For fast push_front() and pop_front() operations, use Deque.
Example code:
@code
Vector<int> v;
printf("%d\n", v.size()); // prints "0"
v.push_back(1);
v.push_back(2);
printf("%d\n", v.size()); // prints "2"
printf("%d %d\n", v[0], v[1]); // prints "1 2"
Vector<int>::iterator it = v.begin();
int *ip = it; // Vector iterators are pointers
assert(it == v.end() - 2);
v.erase(v.begin());
printf("%d\n", v.size()); // prints "1"
printf("%d\n", v[0]); // prints "2"
@endcode
*/
template <typename T>
class Vector {
typedef typename array_memory<T>::type array_memory_type;
mutable vector_memory<array_memory_type> vm_;
public:
typedef T value_type; ///< Value type.
typedef T &reference; ///< Reference to value type.
typedef const T &const_reference; ///< Const reference to value type.
typedef T *pointer; ///< Pointer to value type.
typedef const T *const_pointer; ///< Pointer to const value type.
/** @brief Type used for value arguments (either T or const T &). */
typedef typename fast_argument<T>::type value_argument_type;
typedef const T &const_access_type;
typedef int size_type; ///< Type of sizes (size()).
typedef T *iterator; ///< Iterator type.
typedef const T *const_iterator; ///< Const iterator type.
/** @brief Constant passed to reserve() to grow the Vector. */
enum { RESERVE_GROW = (size_type) -1 };
explicit inline Vector();
explicit inline Vector(size_type n, value_argument_type v);
inline Vector(const Vector<T> &x);
#if HAVE_CXX_RVALUE_REFERENCES
inline Vector(Vector<T> &&x);
#endif
inline Vector<T> &operator=(const Vector<T> &x);
#if HAVE_CXX_RVALUE_REFERENCES
inline Vector<T> &operator=(Vector<T> &&x);
#endif
inline Vector<T> &assign(size_type n, value_argument_type v = T());
inline iterator begin();
inline iterator end();
inline const_iterator begin() const;
inline const_iterator end() const;
inline const_iterator cbegin() const;
inline const_iterator cend() const;
inline size_type size() const;
inline size_type capacity() const;
inline bool empty() const;
inline void resize(size_type n, value_argument_type v = T());
inline bool reserve(size_type n);
inline T &operator[](size_type i);
inline const T &operator[](size_type i) const;
inline T &at(size_type i);
inline const T &at(size_type i) const;
inline T &front();
inline const T &front() const;
inline T &back();
inline const T &back() const;
inline T &unchecked_at(size_type i);
inline const T &unchecked_at(size_type i) const;
inline T &at_u(size_type i) CLICK_DEPRECATED;
inline const T &at_u(size_type i) const CLICK_DEPRECATED;
inline T *data();
inline const T *data() const;
inline void push_back(value_argument_type v);
#if HAVE_CXX_RVALUE_REFERENCES
template <typename A = fast_argument<T> >
inline typename A::enable_rvalue_reference push_back(T &&v);
#endif
inline void pop_back();
inline void push_front(value_argument_type v);
inline void pop_front();
inline iterator insert(iterator it, value_argument_type v);
inline iterator erase(iterator it);
inline iterator erase(iterator a, iterator b);
inline void clear();
inline void swap(Vector<T> &x);
};
/** @brief Construct an empty vector. */
template <typename T>
inline Vector<T>::Vector() {
}
/** @brief Construct a vector containing @a n copies of @a v. */
template <typename T>
inline Vector<T>::Vector(size_type n, value_argument_type v) {
vm_.resize(n, array_memory_type::cast(&v));
}
/** @brief Construct a vector as a copy of @a x. */
template <typename T>
inline Vector<T>::Vector(const Vector<T> &x) {
vm_.assign(x.vm_);
}
#if HAVE_CXX_RVALUE_REFERENCES
/** @overload */
template <typename T>
inline Vector<T>::Vector(Vector<T> &&x) {
vm_.swap(x.vm_);
}
#endif
/** @brief Return the number of elements. */
template <typename T>
inline typename Vector<T>::size_type Vector<T>::size() const {
return vm_.n_;
}
/** @brief Test if the vector is empty (size() == 0). */
template <typename T>
inline bool Vector<T>::empty() const {
return vm_.n_ == 0;
}
/** @brief Return the vector's capacity.
The capacity is greater than or equal to the size(). Functions such as
resize(n) will not allocate new memory for the vector if n <=
capacity(). */
template <typename T>
inline typename Vector<T>::size_type Vector<T>::capacity() const {
return vm_.capacity_;
}
/** @brief Return an iterator for the first element in the vector. */
template <typename T>
inline typename Vector<T>::iterator Vector<T>::begin() {
return (iterator) vm_.l_;
}
/** @overload */
template <typename T>
inline typename Vector<T>::const_iterator Vector<T>::begin() const {
return (const_iterator) vm_.l_;
}
/** @brief Return an iterator for the end of the vector.
@invariant end() == begin() + size() */
template <typename T>
inline typename Vector<T>::iterator Vector<T>::end() {
return (iterator) vm_.l_ + vm_.n_;
}
/** @overload */
template <typename T>
inline typename Vector<T>::const_iterator Vector<T>::end() const {
return (const_iterator) vm_.l_ + vm_.n_;
}
/** @brief Return a const_iterator for the beginning of the vector. */
template <typename T>
inline typename Vector<T>::const_iterator Vector<T>::cbegin() const {
return (const_iterator) vm_.l_;
}
/** @brief Return a const_iterator for the end of the vector.
@invariant cend() == cbegin() + size() */
template <typename T>
inline typename Vector<T>::const_iterator Vector<T>::cend() const {
return (iterator) vm_.l_ + vm_.n_;
}
/** @brief Return a reference to the <em>i</em>th element.
@pre 0 <= @a i < size() */
template <typename T>
inline T &Vector<T>::operator[](size_type i) {
assert((unsigned) i < (unsigned) vm_.n_);
return *(T *)&vm_.l_[i];
}
/** @overload */
template <typename T>
inline const T &Vector<T>::operator[](size_type i) const {
assert((unsigned) i < (unsigned) vm_.n_);
return *(T *)&vm_.l_[i];
}
/** @brief Return a reference to the <em>i</em>th element.
@pre 0 <= @a i < size()
@sa operator[]() */
template <typename T>
inline T &Vector<T>::at(size_type i) {
return operator[](i);
}
/** @overload */
template <typename T>
inline const T &Vector<T>::at(size_type i) const {
return operator[](i);
}
/** @brief Return a reference to the first element.
@pre !empty() */
template <typename T>
inline T &Vector<T>::front() {
return operator[](0);
}
/** @overload */
template <typename T>
inline const T &Vector<T>::front() const {
return operator[](0);
}
/** @brief Return a reference to the last element (number size()-1).
@pre !empty() */
template <typename T>
inline T &Vector<T>::back() {
return operator[](vm_.n_ - 1);
}
/** @overload */
template <typename T>
inline const T &Vector<T>::back() const {
return operator[](vm_.n_ - 1);
}
/** @brief Return a reference to the <em>i</em>th element.
@pre 0 <= @a i < size()
Unlike operator[]() and at(), this function does not check bounds,
even if assertions are enabled. Use with caution. */
template <typename T>
inline T &Vector<T>::unchecked_at(size_type i) {
return *(T *)&vm_.l_[i];
}
/** @overload */
template <typename T>
inline const T &Vector<T>::unchecked_at(size_type i) const {
return *(T *)&vm_.l_[i];
}
/** @cond never */
template <typename T>
inline T &Vector<T>::at_u(size_type i) {
return unchecked_at(i);
}
template <typename T>
inline const T &Vector<T>::at_u(size_type i) const {
return unchecked_at(i);
}
/** @endcond never */
/** @brief Return a pointer to the vector's data.
May be null if empty(). */
template <typename T>
inline T *Vector<T>::data() {
return (T *) vm_.l_;
}
/** @overload */
template <typename T>
inline const T *Vector<T>::data() const {
return (const T *) vm_.l_;
}
/** @brief Resize the vector to contain @a n elements.
@param n new size
@param v value used to fill new elements */
template <typename T>
inline void Vector<T>::resize(size_type n, value_argument_type v) {
vm_.resize(n, array_memory_type::cast(&v));
}
/** @brief Append element @a v.
A copy of @a v is inserted at position size(). Takes amortized O(1)
time. */
template <typename T>
inline void Vector<T>::push_back(value_argument_type v) {
vm_.push_back(array_memory_type::cast(&v));
}
#if HAVE_CXX_RVALUE_REFERENCES
/** @overload */
template <typename T> template <typename A>
inline typename A::enable_rvalue_reference Vector<T>::push_back(T&& v)
{
vm_.move_construct_back(array_memory_type::cast(&v));
}
#endif
/** @brief Remove the last element.
Takes O(1) time. */
template <typename T>
inline void Vector<T>::pop_back() {
vm_.pop_back();
}
/** @brief Prepend element @a v.
A copy of @a v is added to position 0. Other elements are shifted one
position forward. Takes O(size()) time. */
template <typename T>
inline void Vector<T>::push_front(value_argument_type v) {
vm_.insert(vm_.l_, array_memory_type::cast(&v));
}
/** @brief Remove the first element.
Other elements are shifted one position backward. Takes O(size())
time. */
template <typename T>
inline void Vector<T>::pop_front() {
vm_.erase(vm_.l_, vm_.l_ + 1);
}
/** @brief Insert @a v before position @a it.
@return An iterator pointing at the new element. */
template <typename T>
inline typename Vector<T>::iterator
Vector<T>::insert(iterator it, value_argument_type v) {
return (iterator) vm_.insert(array_memory_type::cast(it),
array_memory_type::cast(&v));
}
/** @brief Remove the element at position @a it.
@return An iterator pointing at the element following @a it. */
template <typename T>
inline typename Vector<T>::iterator
Vector<T>::erase(iterator it) {
return (it < end() ? erase(it, it + 1) : it);
}
/** @brief Remove the elements in [@a a, @a b).
@return An iterator corresponding to @a b. */
template <typename T>
inline typename Vector<T>::iterator
Vector<T>::erase(iterator a, iterator b) {
return (iterator) vm_.erase(array_memory_type::cast(a),
array_memory_type::cast(b));
}
/** @brief Remove all elements.
@post size() == 0 */
template <typename T>
inline void Vector<T>::clear() {
vm_.clear();
}
/** @brief Reserve space for at least @a n more elements.
@return true iff reserve succeeded.
This function changes the vector's capacity(), not its size(). If
reserve(@a n) succeeds, then any succeeding call to resize(@a m) with @a
m < @a n will succeed without allocating vector memory. */
template <typename T>
inline bool Vector<T>::reserve(size_type n) {
return vm_.reserve_and_push_back(n, 0);
}
/** @brief Swap the contents of this vector and @a x. */
template <typename T>
inline void Vector<T>::swap(Vector<T> &x) {
vm_.swap(x.vm_);
}
/** @brief Replace this vector's contents with a copy of @a x. */
template <typename T>
inline Vector<T> &Vector<T>::operator=(const Vector<T> &x) {
vm_.assign(x.vm_);
return *this;
}
#if HAVE_CXX_RVALUE_REFERENCES
template <typename T>
inline Vector<T> &Vector<T>::operator=(Vector<T> &&x) {
vm_.swap(x.vm_);
return *this;
}
#endif
/** @brief Replace this vector's contents with @a n copies of @a v.
@post size() == @a n */
template <typename T>
inline Vector<T> &Vector<T>::assign(size_type n, value_argument_type v) {
vm_.assign(n, array_memory_type::cast(&v));
return *this;
}
template <typename T>
inline void click_swap(Vector<T> &a, Vector<T> &b) {
a.swap(b);
}
template <typename T>
inline void assign_consume(Vector<T> &a, Vector<T> &b) {
a.swap(b);
}
CLICK_ENDDECLS
#include <click/vector.cc>
#endif

View File

@ -0,0 +1,129 @@
#ifndef CLICKNET_DHCP_H
#define CLICKNET_DHCP_H
struct click_dhcp {
uint8_t op; /* message type */
uint8_t htype; /* hardware address type */
uint8_t hlen; /* hardware address length */
uint8_t hops; /* should be zero in client's message */
uint32_t xid; /* transaction id */
uint16_t secs; /* elapsed time in sec. from trying to boot */
uint16_t flags;
uint32_t ciaddr; /* (previously allocated) client IP address */
uint32_t yiaddr; /* 'your' client IP address */
uint32_t siaddr; /* should be zero in client's messages */
uint32_t giaddr; /* should be zero in client's messages */
uint8_t chaddr[16]; /* client's hardware address */
uint8_t sname[64]; /* server host name, null terminated string */
uint8_t file[128]; /* boot file name, null terminated string */
uint32_t magic; /* magic cookie */
uint8_t options[312]; /* message options */
} CLICK_SIZE_PACKED_ATTRIBUTE;
#define ETH_10MB 1 /* htype */
#define ETH_10MB_LEN 6 /* hlen */
/* DHCP message OP code */
#define DHCP_BOOTREQUEST 1
#define DHCP_BOOTREPLY 2
/* DHCP Client State*/
enum dhcp_client_state {
DHCP_CLIENT_INIT_STATE = 1,
DHCP_CLIENT_SELECTING_STATE,
DHCP_CLIENT_REQUESTING_STATE,
DHCP_CLIENT_INIT_REBOOT,
DHCP_CLIENT_REBOOTING,
DHCP_CLIENT_BOUND,
DHCP_CLIENT_RENEWING,
DHCP_CLIENT_REBINDING
};
/* DHCP message type */
#define DHCP_DISCOVER 1
#define DHCP_OFFER 2
#define DHCP_REQUEST 3
#define DHCP_DECLINE 4
#define DHCP_ACK 5
#define DHCP_NACK 6
#define DHCP_RELEASE 7
#define DHCP_INFORM 8
#define DHCP_MAGIC 0x63538263
/* DHCP Option codes: */
#define DHO_PAD 0
#define DHO_SUBNET_MASK 1
#define DHO_TIME_OFFSET 2
#define DHO_ROUTERS 3
#define DHO_TIME_SERVERS 4
#define DHO_NAME_SERVERS 5
#define DHO_DOMAIN_NAME_SERVERS 6
#define DHO_LOG_SERVERS 7
#define DHO_COOKIE_SERVERS 8
#define DHO_LPR_SERVERS 9
#define DHO_IMPRESS_SERVERS 10
#define DHO_RESOURCE_LOCATION_SERVERS 11
#define DHO_HOST_NAME 12
#define DHO_BOOT_SIZE 13
#define DHO_MERIT_DUMP 14
#define DHO_DOMAIN_NAME 15
#define DHO_SWAP_SERVER 16
#define DHO_ROOT_PATH 17
#define DHO_EXTENSIONS_PATH 18
#define DHO_IP_FORWARDING 19
#define DHO_NON_LOCAL_SOURCE_ROUTING 20
#define DHO_POLICY_FILTER 21
#define DHO_MAX_DGRAM_REASSEMBLY 22
#define DHO_DEFAULT_IP_TTL 23
#define DHO_PATH_MTU_AGING_TIMEOUT 24
#define DHO_PATH_MTU_PLATEAU_TABLE 25
#define DHO_INTERFACE_MTU 26
#define DHO_ALL_SUBNETS_LOCAL 27
#define DHO_BROADCAST_ADDRESS 28
#define DHO_PERFORM_MASK_DISCOVERY 29
#define DHO_MASK_SUPPLIER 30
#define DHO_ROUTER_DISCOVERY 31
#define DHO_ROUTER_SOLICITATION_ADDRESS 32
#define DHO_STATIC_ROUTES 33
#define DHO_TRAILER_ENCAPSULATION 34
#define DHO_ARP_CACHE_TIMEOUT 35
#define DHO_IEEE802_3_ENCAPSULATION 36
#define DHO_DEFAULT_TCP_TTL 37
#define DHO_TCP_KEEPALIVE_INTERVAL 38
#define DHO_TCP_KEEPALIVE_GARBAGE 39
#define DHO_NIS_DOMAIN 40
#define DHO_NIS_SERVERS 41
#define DHO_NTP_SERVERS 42
#define DHO_VENDOR_ENCAPSULATED_OPTIONS 43
#define DHO_NETBIOS_NAME_SERVERS 44
#define DHO_NETBIOS_DD_SERVER 45
#define DHO_NETBIOS_NODE_TYPE 46
#define DHO_NETBIOS_SCOPE 47
#define DHO_FONT_SERVERS 48
#define DHO_X_DISPLAY_MANAGER 49
#define DHO_DHCP_REQUESTED_ADDRESS 50
#define DHO_DHCP_LEASE_TIME 51
#define DHO_DHCP_OPTION_OVERLOAD 52
#define DHO_DHCP_MESSAGE_TYPE 53
#define DHO_DHCP_SERVER_IDENTIFIER 54
#define DHO_DHCP_PARAMETER_REQUEST_LIST 55
#define DHO_DHCP_MESSAGE 56
#define DHO_DHCP_MAX_MESSAGE_SIZE 57
#define DHO_DHCP_RENEWAL_TIME 58
#define DHO_DHCP_REBINDING_TIME 59
#define DHO_VENDOR_CLASS_IDENTIFIER 60
#define DHO_DHCP_CLIENT_IDENTIFIER 61
#define DHO_NWIP_DOMAIN_NAME 62
#define DHO_NWIP_SUBOPTIONS 63
#define DHO_USER_CLASS 77
#define DHO_FQDN 81
#define DHO_DHCP_AGENT_OPTIONS 82
#define DHO_SUBNET_SELECTION 118 /* RFC3011! */
#define DHO_END 255
#endif /* CLICKNET_DHCP_H */

View File

@ -0,0 +1,130 @@
/* -*- mode: c; c-basic-offset: 4 -*- */
#ifndef CLICKNET_ETHER_H
#define CLICKNET_ETHER_H
/*
* <clicknet/ether.h> -- Ethernet and ARP headers, based on one of the BSDs.
*
* Relevant RFCs include:
* RFC826 Ethernet Address Resolution Protocol: or, Converting Network
* Protocol Addresses to 48.bit Ethernet Address for Transmission
* on Ethernet Hardware
* RFC894 Standard for the transmission of IP datagrams over Ethernet
* networks
* Also see the relevant IEEE 802 standards.
*/
struct click_ether {
uint8_t ether_dhost[6]; /* 0-5 Ethernet destination address */
uint8_t ether_shost[6]; /* 6-11 Ethernet source address */
uint16_t ether_type; /* 12-13 Ethernet protocol */
} CLICK_SIZE_PACKED_ATTRIBUTE;
#define ETHERTYPE_IP 0x0800
#define ETHERTYPE_ARP 0x0806
#define ETHERTYPE_TRAIL 0x1000
#define ETHERTYPE_8021Q 0x8100
#define ETHERTYPE_IP6 0x86DD
#define ETHERTYPE_MACCONTROL 0x8808
#define ETHERTYPE_PPPOE_DISC 0x8863
#define ETHERTYPE_PPPOE_SESSION 0x8864
#define ETHERTYPE_GRID 0x7fff /* wvlan_cs driver won't transmit frames with high bit of protocol number set */
struct click_arp { /* Offsets relative to ARP (Ethernet) header */
uint16_t ar_hrd; /* 0-1 (14-15) hardware address format */
#define ARPHRD_ETHER 1 /* Ethernet 10Mbps */
#define ARPHRD_IEEE802 6 /* token ring */
#define ARPHRD_ARCNET 7 /* Arcnet */
#define ARPHRD_FRELAY 15 /* frame relay */
#define ARPHRD_STRIP 23 /* Ricochet Starmode Radio */
#define ARPHRD_IEEE1394 24 /* IEEE 1394 (FireWire) */
#define ARPHRD_80211 801 /* IEEE 802.11 (wifi) */
uint16_t ar_pro; /* 2-3 (16-17) protocol address format */
uint8_t ar_hln; /* 4 (18) hardware address length */
uint8_t ar_pln; /* 5 (19) protocol address length */
uint16_t ar_op; /* 6-7 (20-21) opcode (command) */
#define ARPOP_REQUEST 1 /* ARP request */
#define ARPOP_REPLY 2 /* ARP reply */
#define ARPOP_REVREQUEST 3 /* reverse request: hw->proto */
#define ARPOP_REVREPLY 4 /* reverse reply */
#define ARPOP_INVREQUEST 8 /* peer identification req */
#define ARPOP_INVREPLY 9 /* peer identification reply */
};
struct click_ether_arp {
struct click_arp ea_hdr; /* 0-7 (14-21) fixed-size ARP header */
uint8_t arp_sha[6]; /* 8-13 (22-27) sender hardware address */
uint8_t arp_spa[4]; /* 14-17 (28-31) sender protocol address */
uint8_t arp_tha[6]; /* 18-23 (32-37) target hardware address */
uint8_t arp_tpa[4]; /* 24-27 (38-41) target protocol address */
};
/* Ethernet with VLAN (802.1q) */
struct click_ether_vlan {
uint8_t ether_dhost[6]; /* 0-5 Ethernet source address */
uint8_t ether_shost[6]; /* 6-11 Ethernet destination address */
uint16_t ether_vlan_proto; /* 12-13 == ETHERTYPE_8021Q */
uint16_t ether_vlan_tci; /* 14-15 tag control information */
uint16_t ether_vlan_encap_proto; /* 16-17 Ethernet protocol */
} CLICK_SIZE_PACKED_ATTRIBUTE;
/* Ethernet MAC control (802.3) */
struct click_ether_macctl {
uint16_t ether_macctl_opcode;
uint16_t ether_macctl_param;
uint8_t ether_macctl_reserved[42];
};
#define ETHER_MACCTL_OP_PAUSE 0x0001
#define ND_SOL 0x0087 /* Neighborhood Solicitation Message Type */
#define ND_ADV 0x0088 /* Neighborhood Advertisement Message Type */
/* define structure of Neighborhood Solicitation Message */
struct click_nd_sol {
uint8_t type;
uint8_t code;
uint16_t checksum;
uint32_t reserved;
uint8_t nd_tpa[16];
uint8_t option_type; /*option type: 1 (source link-layer add) */
uint8_t option_length; /*option length: 1 (in units of 8 octets) */
uint8_t nd_sha[6]; /*source link-layer address */
};
/* define structure of Neighborhood Advertisement Message -reply to multicast neighborhood solitation message */
struct click_nd_adv {
uint8_t type;
uint8_t code;
uint16_t checksum;
uint8_t flags; /* bit 1: sender_is_router
bit 2: solicited
bit 3: override
all other bits should be zero */
uint8_t reserved[3];
uint8_t nd_tpa[16];
uint8_t option_type; /* option type: 2 (target link-layer add) */
uint8_t option_length; /* option length: 1 (in units of 8 octets) */
uint8_t nd_tha[6]; /* source link-layer address */
};
/* define structure of Neighborhood Advertisement Message - reply to unicast neighborhood solitation message */
struct click_nd_adv2 {
uint8_t type;
uint8_t code;
uint16_t checksum;
uint8_t flags; /* bit 1: sender_is_router
bit 2: solicited
bit 3: override
all other bits should be zero */
uint8_t reserved[3];
uint8_t nd_tpa[16];
};
#endif

Some files were not shown because too many files have changed in this diff Show More