openflow build environment setup
This commit is contained in:
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
openbox/
|
||||
openbox_1/
|
||||
include.tgz
|
||||
lib.tgz
|
||||
case.tgz
|
||||
@ -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.
94
openflow/include/click/algorithm.hh
Normal file
94
openflow/include/click/algorithm.hh
Normal 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
|
||||
76
openflow/include/click/archive.hh
Normal file
76
openflow/include/click/archive.hh
Normal 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
|
||||
1409
openflow/include/click/args.hh
Normal file
1409
openflow/include/click/args.hh
Normal file
File diff suppressed because it is too large
Load Diff
121
openflow/include/click/array_memory.hh
Normal file
121
openflow/include/click/array_memory.hh
Normal 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
|
||||
652
openflow/include/click/atomic.hh
Normal file
652
openflow/include/click/atomic.hh
Normal 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
|
||||
19
openflow/include/click/bighashmap.cc
Normal file
19
openflow/include/click/bighashmap.cc
Normal 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>
|
||||
7
openflow/include/click/bighashmap.hh
Normal file
7
openflow/include/click/bighashmap.hh
Normal 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
|
||||
101
openflow/include/click/bighashmap_arena.hh
Normal file
101
openflow/include/click/bighashmap_arena.hh
Normal 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
|
||||
391
openflow/include/click/bigint.hh
Normal file
391
openflow/include/click/bigint.hh
Normal 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
|
||||
379
openflow/include/click/bitvector.hh
Normal file
379
openflow/include/click/bitvector.hh
Normal 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
|
||||
334
openflow/include/click/clp.h
Normal file
334
openflow/include/click/clp.h
Normal 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
|
||||
87
openflow/include/click/config-bsdmodule.h
Normal file
87
openflow/include/click/config-bsdmodule.h
Normal 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 */
|
||||
283
openflow/include/click/config-linuxmodule.h
Normal file
283
openflow/include/click/config-linuxmodule.h
Normal 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 */
|
||||
215
openflow/include/click/config-minios.h
Normal file
215
openflow/include/click/config-minios.h
Normal 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 */
|
||||
23
openflow/include/click/config-ns.h
Normal file
23
openflow/include/click/config-ns.h
Normal 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 */
|
||||
348
openflow/include/click/config-userlevel.h
Normal file
348
openflow/include/click/config-userlevel.h
Normal 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 */
|
||||
333
openflow/include/click/config.h
Normal file
333
openflow/include/click/config.h
Normal 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 */
|
||||
743
openflow/include/click/confparse.hh
Normal file
743
openflow/include/click/confparse.hh
Normal 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
|
||||
14
openflow/include/click/crc32.h
Normal file
14
openflow/include/click/crc32.h
Normal 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
|
||||
25
openflow/include/click/cxxprotect.h
Normal file
25
openflow/include/click/cxxprotect.h
Normal 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
|
||||
14
openflow/include/click/cxxunprotect.h
Normal file
14
openflow/include/click/cxxunprotect.h
Normal 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
|
||||
211
openflow/include/click/deque.cc
Normal file
211
openflow/include/click/deque.cc
Normal 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
|
||||
687
openflow/include/click/deque.hh
Normal file
687
openflow/include/click/deque.hh
Normal 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
|
||||
5
openflow/include/click/dequeue.hh
Normal file
5
openflow/include/click/dequeue.hh
Normal 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
|
||||
210
openflow/include/click/dpdkdevice.hh
Normal file
210
openflow/include/click/dpdkdevice.hh
Normal 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
|
||||
43
openflow/include/click/driver.hh
Normal file
43
openflow/include/click/driver.hh
Normal 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
|
||||
729
openflow/include/click/element.hh
Normal file
729
openflow/include/click/element.hh
Normal 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
|
||||
64
openflow/include/click/elemfilter.hh
Normal file
64
openflow/include/click/elemfilter.hh
Normal 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
|
||||
887
openflow/include/click/error.hh
Normal file
887
openflow/include/click/error.hh
Normal 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
|
||||
230
openflow/include/click/etheraddress.hh
Normal file
230
openflow/include/click/etheraddress.hh
Normal 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 ¶meter_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
|
||||
521
openflow/include/click/ewma.hh
Normal file
521
openflow/include/click/ewma.hh
Normal 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
|
||||
24
openflow/include/click/fixconfig.h
Normal file
24
openflow/include/click/fixconfig.h
Normal 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
|
||||
96
openflow/include/click/fromfile.hh
Normal file
96
openflow/include/click/fromfile.hh
Normal 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
|
||||
240
openflow/include/click/gaprate.hh
Normal file
240
openflow/include/click/gaprate.hh
Normal 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
|
||||
702
openflow/include/click/glue.hh
Normal file
702
openflow/include/click/glue.hh
Normal 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
|
||||
337
openflow/include/click/handler.hh
Normal file
337
openflow/include/click/handler.hh
Normal 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 ¶m, 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
|
||||
577
openflow/include/click/handlercall.hh
Normal file
577
openflow/include/click/handlercall.hh
Normal 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
|
||||
103
openflow/include/click/hashallocator.hh
Normal file
103
openflow/include/click/hashallocator.hh
Normal 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
|
||||
103
openflow/include/click/hashcode.hh
Normal file
103
openflow/include/click/hashcode.hh
Normal 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
|
||||
724
openflow/include/click/hashcontainer.hh
Normal file
724
openflow/include/click/hashcontainer.hh
Normal 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
|
||||
723
openflow/include/click/hashmap.cc
Normal file
723
openflow/include/click/hashmap.cc
Normal 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
|
||||
585
openflow/include/click/hashmap.hh
Normal file
585
openflow/include/click/hashmap.hh
Normal 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
|
||||
1120
openflow/include/click/hashtable.hh
Normal file
1120
openflow/include/click/hashtable.hh
Normal file
File diff suppressed because it is too large
Load Diff
425
openflow/include/click/heap.hh
Normal file
425
openflow/include/click/heap.hh
Normal 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
|
||||
133
openflow/include/click/ino.hh
Normal file
133
openflow/include/click/ino.hh
Normal 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
|
||||
503
openflow/include/click/integers.hh
Normal file
503
openflow/include/click/integers.hh
Normal 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 = a / b;
|
||||
return a - quot * b;
|
||||
}
|
||||
|
||||
/** @overload */
|
||||
inline int32_t int_remainder(int32_t a, uint32_t b, int32_t ") {
|
||||
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 ") {
|
||||
# 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 ") {
|
||||
# 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
|
||||
408
openflow/include/click/ip6address.hh
Normal file
408
openflow/include/click/ip6address.hh
Normal 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 ¶meter_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
|
||||
250
openflow/include/click/ip6flowid.hh
Normal file
250
openflow/include/click/ip6flowid.hh
Normal 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
|
||||
39
openflow/include/click/ip6table.hh
Normal file
39
openflow/include/click/ip6table.hh
Normal 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
|
||||
419
openflow/include/click/ipaddress.hh
Normal file
419
openflow/include/click/ipaddress.hh
Normal 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
|
||||
1
openflow/include/click/ipaddresslist.hh
Normal file
1
openflow/include/click/ipaddresslist.hh
Normal file
@ -0,0 +1 @@
|
||||
#error "The IPAddressList class is no longer available. Use Vector<IPAddress> instead."
|
||||
192
openflow/include/click/ipflowid.hh
Normal file
192
openflow/include/click/ipflowid.hh
Normal 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
|
||||
38
openflow/include/click/iptable.hh
Normal file
38
openflow/include/click/iptable.hh
Normal 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
|
||||
252
openflow/include/click/lexer.hh
Normal file
252
openflow/include/click/lexer.hh
Normal 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
|
||||
342
openflow/include/click/libdivide.h
Normal file
342
openflow/include/click/libdivide.h
Normal 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
|
||||
564
openflow/include/click/list.hh
Normal file
564
openflow/include/click/list.hh
Normal 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 */
|
||||
195
openflow/include/click/llrpc.h
Normal file
195
openflow/include/click/llrpc.h
Normal 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
|
||||
82
openflow/include/click/machine.hh
Normal file
82
openflow/include/click/machine.hh
Normal 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
|
||||
223
openflow/include/click/master.hh
Normal file
223
openflow/include/click/master.hh
Normal 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
|
||||
203
openflow/include/click/md5.h
Normal file
203
openflow/include/click/md5.h
Normal 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
|
||||
|
||||
528
openflow/include/click/nameinfo.hh
Normal file
528
openflow/include/click/nameinfo.hh
Normal 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
|
||||
730
openflow/include/click/notifier.hh
Normal file
730
openflow/include/click/notifier.hh
Normal 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
|
||||
30
openflow/include/click/package.hh
Normal file
30
openflow/include/click/package.hh
Normal 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
|
||||
2434
openflow/include/click/packet.hh
Normal file
2434
openflow/include/click/packet.hh
Normal file
File diff suppressed because it is too large
Load Diff
137
openflow/include/click/packet_anno.hh
Normal file
137
openflow/include/click/packet_anno.hh
Normal 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
|
||||
89
openflow/include/click/pair.hh
Normal file
89
openflow/include/click/pair.hh
Normal 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
|
||||
42
openflow/include/click/pathvars.h
Normal file
42
openflow/include/click/pathvars.h
Normal 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
|
||||
37
openflow/include/click/perfctr-i586.hh
Normal file
37
openflow/include/click/perfctr-i586.hh
Normal 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
|
||||
624
openflow/include/click/router.hh
Normal file
624
openflow/include/click/router.hh
Normal 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
|
||||
527
openflow/include/click/routerthread.hh
Normal file
527
openflow/include/click/routerthread.hh
Normal 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
|
||||
193
openflow/include/click/routervisitor.hh
Normal file
193
openflow/include/click/routervisitor.hh
Normal 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
|
||||
137
openflow/include/click/selectset.hh
Normal file
137
openflow/include/click/selectset.hh
Normal 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
|
||||
118
openflow/include/click/simclick.h
Normal file
118
openflow/include/click/simclick.h
Normal 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
|
||||
16
openflow/include/click/skbmgr.hh
Normal file
16
openflow/include/click/skbmgr.hh
Normal 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
|
||||
135
openflow/include/click/standard/addressinfo.hh
Normal file
135
openflow/include/click/standard/addressinfo.hh
Normal 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
|
||||
48
openflow/include/click/standard/alignmentinfo.hh
Normal file
48
openflow/include/click/standard/alignmentinfo.hh
Normal 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
|
||||
35
openflow/include/click/standard/errorelement.hh
Normal file
35
openflow/include/click/standard/errorelement.hh
Normal 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
|
||||
71
openflow/include/click/standard/portinfo.hh
Normal file
71
openflow/include/click/standard/portinfo.hh
Normal 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
|
||||
104
openflow/include/click/standard/scheduleinfo.hh
Normal file
104
openflow/include/click/standard/scheduleinfo.hh
Normal 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
|
||||
123
openflow/include/click/standard/storage.hh
Normal file
123
openflow/include/click/standard/storage.hh
Normal 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
|
||||
18
openflow/include/click/standard/threadsched.hh
Normal file
18
openflow/include/click/standard/threadsched.hh
Normal 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
|
||||
624
openflow/include/click/straccum.hh
Normal file
624
openflow/include/click/straccum.hh
Normal 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
|
||||
1021
openflow/include/click/string.hh
Normal file
1021
openflow/include/click/string.hh
Normal file
File diff suppressed because it is too large
Load Diff
568
openflow/include/click/sync.hh
Normal file
568
openflow/include/click/sync.hh
Normal 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
|
||||
648
openflow/include/click/task.hh
Normal file
648
openflow/include/click/task.hh
Normal 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
|
||||
397
openflow/include/click/timer.hh
Normal file
397
openflow/include/click/timer.hh
Normal 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
|
||||
162
openflow/include/click/timerset.hh
Normal file
162
openflow/include/click/timerset.hh
Normal 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
|
||||
1540
openflow/include/click/timestamp.hh
Normal file
1540
openflow/include/click/timestamp.hh
Normal file
File diff suppressed because it is too large
Load Diff
1021
openflow/include/click/tokenbucket.hh
Normal file
1021
openflow/include/click/tokenbucket.hh
Normal file
File diff suppressed because it is too large
Load Diff
522
openflow/include/click/type_traits.hh
Normal file
522
openflow/include/click/type_traits.hh
Normal 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
|
||||
97
openflow/include/click/userutils.hh
Normal file
97
openflow/include/click/userutils.hh
Normal 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
|
||||
50
openflow/include/click/variableenv.hh
Normal file
50
openflow/include/click/variableenv.hh
Normal 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
|
||||
165
openflow/include/click/vector.cc
Normal file
165
openflow/include/click/vector.cc
Normal 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
|
||||
518
openflow/include/click/vector.hh
Normal file
518
openflow/include/click/vector.hh
Normal 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
|
||||
129
openflow/include/clicknet/dhcp.h
Normal file
129
openflow/include/clicknet/dhcp.h
Normal 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 */
|
||||
130
openflow/include/clicknet/ether.h
Normal file
130
openflow/include/clicknet/ether.h
Normal 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
Reference in New Issue
Block a user