
Recent kernels support conntrack time stamping, which is a helpful feature to determine the duration of a flow without building a flow cache in your user space application, just to keep the 'start' time of your flow. Timestamps are recorded with nanosecond resolution once this feature is enabled. This patch adds optional support for the CTA_TIMESTAMP, then modifies the dump routine to write that info in a format similar to /proc/net/nf_conntrack. This is an example output when using NL_DUMP_LINE: udp 10.128.128.28:56836 <-> 10.128.129.255:8612 delta-time 30 Signed-off-by: Holger Eitzenberger <holger@eitzenberger.org> Signed-off-by: Thomas Graf <tgraf@suug.ch>
264 lines
6.3 KiB
C
264 lines
6.3 KiB
C
/*
|
|
* netlink-private/netlink.h Local Netlink Interface
|
|
*
|
|
* This library 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 2.1
|
|
* of the License.
|
|
*
|
|
* Copyright (c) 2003-2013 Thomas Graf <tgraf@suug.ch>
|
|
*/
|
|
|
|
#ifndef NETLINK_LOCAL_H_
|
|
#define NETLINK_LOCAL_H_
|
|
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <math.h>
|
|
#include <time.h>
|
|
#include <stdarg.h>
|
|
#include <ctype.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/socket.h>
|
|
#include <inttypes.h>
|
|
#include <assert.h>
|
|
#include <limits.h>
|
|
#include <search.h>
|
|
|
|
#include <arpa/inet.h>
|
|
#include <netdb.h>
|
|
|
|
#include <defs.h>
|
|
|
|
#ifndef SOL_NETLINK
|
|
#define SOL_NETLINK 270
|
|
#endif
|
|
|
|
#include <linux/types.h>
|
|
|
|
/* local header copies */
|
|
#include <linux/if.h>
|
|
#include <linux/if_arp.h>
|
|
#include <linux/if_ether.h>
|
|
#include <linux/ethtool.h>
|
|
#include <linux/pkt_sched.h>
|
|
#include <linux/pkt_cls.h>
|
|
#include <linux/gen_stats.h>
|
|
#include <linux/ip_mp_alg.h>
|
|
#include <linux/atm.h>
|
|
#include <linux/inetdevice.h>
|
|
#include <linux/ipv6.h>
|
|
#include <linux/snmp.h>
|
|
|
|
#ifndef DISABLE_PTHREADS
|
|
#include <pthread.h>
|
|
#endif
|
|
|
|
#include <netlink/netlink.h>
|
|
#include <netlink/handlers.h>
|
|
#include <netlink/cache.h>
|
|
#include <netlink/route/tc.h>
|
|
#include <netlink-private/object-api.h>
|
|
#include <netlink-private/cache-api.h>
|
|
#include <netlink-private/types.h>
|
|
|
|
#define NSEC_PER_SEC 1000000000L
|
|
|
|
struct trans_tbl {
|
|
int i;
|
|
const char *a;
|
|
};
|
|
|
|
#define __ADD(id, name) { .i = id, .a = #name },
|
|
|
|
struct trans_list {
|
|
int i;
|
|
char *a;
|
|
struct nl_list_head list;
|
|
};
|
|
|
|
#ifdef NL_DEBUG
|
|
#define NL_DBG(LVL,FMT,ARG...) \
|
|
do { \
|
|
if (LVL <= nl_debug) \
|
|
fprintf(stderr, \
|
|
"DBG<" #LVL ">%20s:%-4u %s: " FMT, \
|
|
__FILE__, __LINE__, \
|
|
__PRETTY_FUNCTION__, ##ARG); \
|
|
} while (0)
|
|
#else /* NL_DEBUG */
|
|
#define NL_DBG(LVL,FMT,ARG...) do { } while(0)
|
|
#endif /* NL_DEBUG */
|
|
|
|
#define BUG() \
|
|
do { \
|
|
fprintf(stderr, "BUG at file position %s:%d:%s\n", \
|
|
__FILE__, __LINE__, __PRETTY_FUNCTION__); \
|
|
assert(0); \
|
|
} while (0)
|
|
|
|
#define APPBUG(msg) \
|
|
do { \
|
|
fprintf(stderr, "APPLICATION BUG: %s:%d:%s: %s\n", \
|
|
__FILE__, __LINE__, __PRETTY_FUNCTION__, msg); \
|
|
assert(0); \
|
|
} while(0)
|
|
|
|
extern int __nl_read_num_str_file(const char *path,
|
|
int (*cb)(long, const char *));
|
|
|
|
extern int __trans_list_add(int, const char *, struct nl_list_head *);
|
|
extern void __trans_list_clear(struct nl_list_head *);
|
|
|
|
extern char *__type2str(int, char *, size_t, const struct trans_tbl *, size_t);
|
|
extern int __str2type(const char *, const struct trans_tbl *, size_t);
|
|
|
|
extern char *__list_type2str(int, char *, size_t, struct nl_list_head *);
|
|
extern int __list_str2type(const char *, struct nl_list_head *);
|
|
|
|
extern char *__flags2str(int, char *, size_t, const struct trans_tbl *, size_t);
|
|
extern int __str2flags(const char *, const struct trans_tbl *, size_t);
|
|
|
|
extern void dump_from_ops(struct nl_object *, struct nl_dump_params *);
|
|
|
|
static inline int nl_cb_call(struct nl_cb *cb, int type, struct nl_msg *msg)
|
|
{
|
|
return cb->cb_set[type](msg, cb->cb_args[type]);
|
|
}
|
|
|
|
#define ARRAY_SIZE(X) (sizeof(X) / sizeof((X)[0]))
|
|
|
|
/* This is also defined in stddef.h */
|
|
#ifndef offsetof
|
|
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
|
|
#endif
|
|
|
|
#define __init __attribute__ ((constructor))
|
|
#define __exit __attribute__ ((destructor))
|
|
#undef __deprecated
|
|
#define __deprecated __attribute__ ((deprecated))
|
|
|
|
#define min(x,y) ({ \
|
|
typeof(x) _x = (x); \
|
|
typeof(y) _y = (y); \
|
|
(void) (&_x == &_y); \
|
|
_x < _y ? _x : _y; })
|
|
|
|
#define max(x,y) ({ \
|
|
typeof(x) _x = (x); \
|
|
typeof(y) _y = (y); \
|
|
(void) (&_x == &_y); \
|
|
_x > _y ? _x : _y; })
|
|
|
|
#define min_t(type,x,y) \
|
|
({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
|
|
#define max_t(type,x,y) \
|
|
({ type __x = (x); type __y = (y); __x > __y ? __x: __y; })
|
|
|
|
extern int nl_cache_parse(struct nl_cache_ops *, struct sockaddr_nl *,
|
|
struct nlmsghdr *, struct nl_parser_param *);
|
|
|
|
|
|
static inline void rtnl_copy_ratespec(struct rtnl_ratespec *dst,
|
|
struct tc_ratespec *src)
|
|
{
|
|
dst->rs_cell_log = src->cell_log;
|
|
dst->rs_overhead = src->overhead;
|
|
dst->rs_cell_align = src->cell_align;
|
|
dst->rs_mpu = src->mpu;
|
|
dst->rs_rate = src->rate;
|
|
}
|
|
|
|
static inline void rtnl_rcopy_ratespec(struct tc_ratespec *dst,
|
|
struct rtnl_ratespec *src)
|
|
{
|
|
dst->cell_log = src->rs_cell_log;
|
|
dst->overhead = src->rs_overhead;
|
|
dst->cell_align = src->rs_cell_align;
|
|
dst->mpu = src->rs_mpu;
|
|
dst->rate = src->rs_rate;
|
|
}
|
|
|
|
static inline char *nl_cache_name(struct nl_cache *cache)
|
|
{
|
|
return cache->c_ops ? cache->c_ops->co_name : "unknown";
|
|
}
|
|
|
|
#define GENL_FAMILY(id, name) \
|
|
{ \
|
|
{ id, NL_ACT_UNSPEC, name }, \
|
|
END_OF_MSGTYPES_LIST, \
|
|
}
|
|
|
|
static inline int wait_for_ack(struct nl_sock *sk)
|
|
{
|
|
if (sk->s_flags & NL_NO_AUTO_ACK)
|
|
return 0;
|
|
else
|
|
return nl_wait_for_ack(sk);
|
|
}
|
|
|
|
static inline int build_sysconf_path(char **strp, const char *filename)
|
|
{
|
|
char *sysconfdir;
|
|
|
|
sysconfdir = getenv("NLSYSCONFDIR");
|
|
|
|
if (!sysconfdir)
|
|
sysconfdir = SYSCONFDIR;
|
|
|
|
return asprintf(strp, "%s/%s", sysconfdir, filename);
|
|
}
|
|
|
|
#ifndef DISABLE_PTHREADS
|
|
#define NL_LOCK(NAME) pthread_mutex_t (NAME) = PTHREAD_MUTEX_INITIALIZER
|
|
#define NL_RW_LOCK(NAME) pthread_rwlock_t (NAME) = PTHREAD_RWLOCK_INITIALIZER
|
|
|
|
static inline void nl_lock(pthread_mutex_t *lock)
|
|
{
|
|
pthread_mutex_lock(lock);
|
|
}
|
|
|
|
static inline void nl_unlock(pthread_mutex_t *lock)
|
|
{
|
|
pthread_mutex_unlock(lock);
|
|
}
|
|
|
|
static inline void nl_read_lock(pthread_rwlock_t *lock)
|
|
{
|
|
pthread_rwlock_rdlock(lock);
|
|
}
|
|
|
|
static inline void nl_read_unlock(pthread_rwlock_t *lock)
|
|
{
|
|
pthread_rwlock_unlock(lock);
|
|
}
|
|
|
|
static inline void nl_write_lock(pthread_rwlock_t *lock)
|
|
{
|
|
pthread_rwlock_wrlock(lock);
|
|
}
|
|
|
|
static inline void nl_write_unlock(pthread_rwlock_t *lock)
|
|
{
|
|
pthread_rwlock_unlock(lock);
|
|
}
|
|
|
|
#else
|
|
#define NL_LOCK(NAME) int __unused_lock_ ##NAME __attribute__((unused))
|
|
#define NL_RW_LOCK(NAME) int __unused_lock_ ##NAME __attribute__((unused))
|
|
|
|
#define nl_lock(LOCK) do { } while(0)
|
|
#define nl_unlock(LOCK) do { } while(0)
|
|
#define nl_read_lock(LOCK) do { } while(0)
|
|
#define nl_read_unlock(LOCK) do { } while(0)
|
|
#define nl_write_lock(LOCK) do { } while(0)
|
|
#define nl_write_unlock(LOCK) do { } while(0)
|
|
#endif
|
|
|
|
#endif
|