Add support for inet diag Netlink protocol.

- Inet diag allows users to gather low-level socket information.
- This library provides a higher-level API for creating inetdiag requests (via
  idiagnl_connect and idiagnl_send_simple) and parsing the replies (via
  idiagnl_msg_parse). A cache is also provided (via idiagnl_msg_alloc_cache).
- Request and message objects provide APIs for accessing and setting the
  various properties of each.
- This library also allows the user to parse the inetdiag response attributes
  which contain information about traffic class, TOS, congestion, socket
  memory info, and more depending on the kernel version used.
- Includes doxygen documentation.
This commit is contained in:
Joe Damato 2013-07-03 18:40:58 -07:00
parent 89b00119f2
commit 81d2b1d509
18 changed files with 1888 additions and 5 deletions

View File

@ -197,8 +197,10 @@ ALIASES = arg=\param \
"ref_asciidoc{3}=<a href=\"../\1.html#\2\"><b>\3</b></a>" \
"ref_core{2}=\ref_asciidoc{core,\1,\2 (Netlink Core Library Development Guide)}" \
"ref_route{2}=\ref_asciidoc{route,\1,\2 (Netlink Routing Development Guide)}" \
"ref_idiagnl{2}=\ref_asciidoc{idiag,\1,\2 (Netlink Inet Diag Development Guide)}" \
"core_doc{2}=\ref_core{\1,\2}" \
"route_doc{2}=\ref_route{\1,\2}" \
"idiagnl_doc{2}=\ref_idiagnl{\1,\2}" \
"callback=\par Callback Invocation:\n" \
"lowlevel=\copydoc low_level_api"

View File

@ -78,8 +78,12 @@ nobase_libnlinclude_HEADERS = \
netlink/object-api.h \
netlink/route/link/api.h \
netlink/route/link/info-api.h \
netlink/route/tc-api.h
netlink/route/tc-api.h \
netlink/idiag/idiagnl.h \
netlink/idiag/meminfo.h \
netlink/idiag/msg.h \
netlink/idiag/req.h \
netlink/idiag/vegasinfo.h
if ENABLE_CLI
nobase_libnlinclude_HEADERS += \

View File

@ -7,6 +7,7 @@
* of the License.
*
* Copyright (c) 2003-2013 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2013 Sassano Systems LLC <joe@sassanosystems.com>
*/
#ifndef NETLINK_LOCAL_TYPES_H_
@ -17,6 +18,7 @@
#include <netlink/route/qdisc.h>
#include <netlink/route/rtnl.h>
#include <netlink/route/route.h>
#include <netlink/idiag/idiagnl.h>
#include <netlink-private/route/tc-api.h>
#define NL_SOCK_BUFSIZE_SET (1<<0)
@ -909,4 +911,61 @@ struct ematch_quoted {
int index;
};
struct idiagnl_meminfo {
NLHDR_COMMON
uint32_t idiag_rmem;
uint32_t idiag_wmem;
uint32_t idiag_fmem;
uint32_t idiag_tmem;
};
struct idiagnl_vegasinfo {
NLHDR_COMMON
uint32_t tcpv_enabled;
uint32_t tcpv_rttcnt;
uint32_t tcpv_rtt;
uint32_t tcpv_minrtt;
};
struct idiagnl_msg {
NLHDR_COMMON
uint8_t idiag_family;
uint8_t idiag_state;
uint8_t idiag_timer;
uint8_t idiag_retrans;
uint16_t idiag_sport;
uint16_t idiag_dport;
struct nl_addr * idiag_src;
struct nl_addr * idiag_dst;
uint32_t idiag_ifindex;
uint32_t idiag_expires;
uint32_t idiag_rqueue;
uint32_t idiag_wqueue;
uint32_t idiag_uid;
uint32_t idiag_inode;
uint8_t idiag_tos;
uint8_t idiag_tclass;
uint8_t idiag_shutdown;
char * idiag_cong;
struct idiagnl_meminfo * idiag_meminfo;
struct idiagnl_vegasinfo * idiag_vegasinfo;
struct tcp_info idiag_tcpinfo;
uint32_t idiag_skmeminfo[IDIAG_SK_MEMINFO_VARS];
};
struct idiagnl_req {
NLHDR_COMMON
uint8_t idiag_family;
uint8_t idiag_ext;
struct nl_addr * idiag_src;
struct nl_addr * idiag_dst;
uint32_t idiag_ifindex;
uint32_t idiag_states;
uint32_t idiag_dbs;
};
#endif

View File

@ -0,0 +1,126 @@
/*
* netlink/idiag/idiagnl.h Inetdiag Netlink
*
* 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) 2013 Sassano Systems LLC <joe@sassanosystems.com>
*/
#ifndef NETLINK_IDIAGNL_H_
#define NETLINK_IDIAGNL_H_
#include <netlink/netlink.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* Inet Diag message types
*/
#define IDIAG_TCPDIAG_GETSOCK 18
#define IDIAG_DCCPDIAG_GETSOCK 19
#define IDIAG_GETSOCK_MAX 24
/**
* Socket state identifiers
* @ingroup idiag
*/
enum {
IDIAG_SS_UNKNOWN,
IDIAG_SS_ESTABLISHED,
IDIAG_SS_SYN_SENT,
IDIAG_SS_SYN_RECV,
IDIAG_SS_FIN_WAIT1,
IDIAG_SS_FIN_WAIT2,
IDIAG_SS_TIME_WAIT,
IDIAG_SS_CLOSE,
IDIAG_SS_CLOSE_WAIT,
IDIAG_SS_LAST_ACK,
IDIAG_SS_LISTEN,
IDIAG_SS_CLOSING,
IDIAG_SS_MAX
};
/**
* Macro to represent all socket states.
* @ingroup idiag
*/
#define IDIAG_SS_ALL ((1<<IDIAG_SS_MAX)-1)
/**
* Inet Diag extended attributes
* @ingroup idiag
*/
enum {
IDIAG_ATTR_NONE,
IDIAG_ATTR_MEMINFO,
IDIAG_ATTR_INFO,
IDIAG_ATTR_VEGASINFO,
IDIAG_ATTR_CONG,
IDIAG_ATTR_TOS,
IDIAG_ATTR_TCLASS,
IDIAG_ATTR_SKMEMINFO,
IDIAG_ATTR_SHUTDOWN,
IDIAG_ATTR_MAX,
};
/**
* Macro to represent all socket attributes.
* @ingroup idiag
*/
#define IDIAG_ATTR_ALL ((1<<IDIAG_ATTR_MAX)-1)
/**
* Socket memory info identifiers
* @ingroup idiag
*/
enum {
IDIAG_SK_MEMINFO_RMEM_ALLOC,
IDIAG_SK_MEMINFO_RCVBUF,
IDIAG_SK_MEMINFO_WMEM_ALLOC,
IDIAG_SK_MEMINFO_SNDBUF,
IDIAG_SK_MEMINFO_FWD_ALLOC,
IDIAG_SK_MEMINFO_WMEM_QUEUED,
IDIAG_SK_MEMINFO_OPTMEM,
IDIAG_SK_MEMINFO_BACKLOG,
IDIAG_SK_MEMINFO_VARS,
};
/**
* Socket timer indentifiers
* @ingroupd idiag
*/
enum {
IDIAG_TIMER_OFF,
IDIAG_TIMER_ON,
IDIAG_TIMER_KEEPALIVE,
IDIAG_TIMER_TIMEWAIT,
IDIAG_TIMER_PERSIST,
IDIAG_TIMER_UNKNOWN,
};
extern char * idiagnl_state2str(int, char *, size_t);
extern int idiagnl_str2state(const char *);
extern int idiagnl_connect(struct nl_sock *);
extern int idiagnl_send_simple(struct nl_sock *, int, uint8_t, uint16_t,
uint16_t);
extern char * idiagnl_timer2str(int, char *, size_t);
extern int idiagnl_str2timer(const char *);
extern char * idiagnl_attrs2str(int, char *, size_t);
extern char * idiagnl_tcpstate2str(uint8_t, char *, size_t);
extern char * idiagnl_tcpopts2str(uint8_t, char *, size_t);
extern char * idiagnl_shutdown2str(uint8_t, char *, size_t);
extern char * idiagnl_exts2str(uint8_t, char *, size_t);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* NETLINK_IDIAGNL_H_ */

View File

@ -0,0 +1,41 @@
/*
* netlink/idiag/meminfo.h Inetdiag Netlink Memory Info
*
* 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) 2013 Sassano Systems LLC <joe@sassanosystems.com>
*/
#ifndef NETLINK_IDIAGNL_MEMINFO_H_
#define NETLINK_IDIAGNL_MEMINFO_H_
#include <netlink/netlink.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
extern struct nl_object_ops idiagnl_meminfo_obj_ops;
extern struct idiagnl_meminfo *idiagnl_meminfo_alloc(void);
extern void idiagnl_meminfo_get(struct idiagnl_meminfo *);
extern void idiagnl_meminfo_put(struct idiagnl_meminfo *);
extern uint32_t idiagnl_meminfo_get_rmem(const struct idiagnl_meminfo *);
extern uint32_t idiagnl_meminfo_get_wmem(const struct idiagnl_meminfo *);
extern uint32_t idiagnl_meminfo_get_fmem(const struct idiagnl_meminfo *);
extern uint32_t idiagnl_meminfo_get_tmem(const struct idiagnl_meminfo *);
extern void idiagnl_meminfo_set_rmem(struct idiagnl_meminfo *, uint32_t);
extern void idiagnl_meminfo_set_wmem(struct idiagnl_meminfo *, uint32_t);
extern void idiagnl_meminfo_set_fmem(struct idiagnl_meminfo *, uint32_t);
extern void idiagnl_meminfo_set_tmem(struct idiagnl_meminfo *, uint32_t);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* NETLINK_IDIAGNL_MEMINFO_H_ */

View File

@ -0,0 +1,83 @@
/*
* netlink/idiag/msg.h Inetdiag Netlink Message
*
* 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) 2013 Sassano Systems LLC <joe@sassanosystems.com>
*/
#ifndef NETLINK_IDIAGNL_MSG_H_
#define NETLINK_IDIAGNL_MSG_H_
#include <netlink/netlink.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
struct idiagnl_msg;
extern struct nl_object_ops idiagnl_msg_obj_ops;
extern struct idiagnl_msg * idiagnl_msg_alloc(void);
extern int idiagnl_msg_alloc_cache(struct nl_sock *, int, int,
struct nl_cache**);
extern void idiagnl_msg_get(struct idiagnl_msg *);
extern void idiagnl_msg_put(struct idiagnl_msg *);
extern uint8_t idiagnl_msg_get_family(const struct idiagnl_msg *);
extern void idiagnl_msg_set_family(struct idiagnl_msg *, uint8_t);
extern uint8_t idiagnl_msg_get_state(const struct idiagnl_msg *);
extern void idiagnl_msg_set_state(struct idiagnl_msg *, uint8_t);
extern uint8_t idiagnl_msg_get_timer(const struct idiagnl_msg *);
extern void idiagnl_msg_set_timer(struct idiagnl_msg *, uint8_t);
extern uint8_t idiagnl_msg_get_retrans(const struct idiagnl_msg *);
extern void idiagnl_msg_set_retrans(struct idiagnl_msg *, uint8_t);
extern uint16_t idiagnl_msg_get_sport(struct idiagnl_msg *);
extern void idiagnl_msg_set_sport(struct idiagnl_msg *, uint16_t);
extern uint16_t idiagnl_msg_get_dport(struct idiagnl_msg *);
extern void idiagnl_msg_set_dport(struct idiagnl_msg *, uint16_t);
extern struct nl_addr * idiagnl_msg_get_src(const struct idiagnl_msg *);
extern int idiagnl_msg_set_src(struct idiagnl_msg *,
struct nl_addr *);
extern struct nl_addr * idiagnl_msg_get_dst(const struct idiagnl_msg *);
extern int idiagnl_msg_set_dst(struct idiagnl_msg *,
struct nl_addr *);
extern uint32_t idiagnl_msg_get_ifindex(const struct idiagnl_msg *);
extern void idiagnl_msg_set_ifindex(struct idiagnl_msg *, uint32_t);
extern uint32_t idiagnl_msg_get_expires(const struct idiagnl_msg *);
extern void idiagnl_msg_set_expires(struct idiagnl_msg *, uint32_t);
extern uint32_t idiagnl_msg_get_rqueue(const struct idiagnl_msg *);
extern void idiagnl_msg_set_rqueue(struct idiagnl_msg *, uint32_t);
extern uint32_t idiagnl_msg_get_wqueue(const struct idiagnl_msg *);
extern void idiagnl_msg_set_wqueue(struct idiagnl_msg *, uint32_t);
extern uint32_t idiagnl_msg_get_uid(const struct idiagnl_msg *);
extern void idiagnl_msg_set_uid(struct idiagnl_msg *, uint32_t);
extern uint32_t idiagnl_msg_get_inode(const struct idiagnl_msg *);
extern void idiagnl_msg_set_inode(struct idiagnl_msg *, uint32_t);
extern uint8_t idiagnl_msg_get_tos(const struct idiagnl_msg *);
extern void idiagnl_msg_set_tos(struct idiagnl_msg *, uint8_t);
extern uint8_t idiagnl_msg_get_tclass(const struct idiagnl_msg *);
extern void idiagnl_msg_set_tclass(struct idiagnl_msg *, uint8_t);
extern uint8_t idiagnl_msg_get_shutdown(const struct idiagnl_msg *);
extern void idiagnl_msg_set_shutdown(struct idiagnl_msg *, uint8_t);
extern char * idiagnl_msg_get_cong(const struct idiagnl_msg *);
extern void idiagnl_msg_set_cong(struct idiagnl_msg *, char *);
extern struct idiagnl_meminfo *idiagnl_msg_get_meminfo(const struct idiagnl_msg *);
extern void idiagnl_msg_set_meminfo(struct idiagnl_msg *,
struct idiagnl_meminfo *);
extern struct idiagnl_vegasinfo *idiagnl_msg_get_vegasinfo(const struct idiagnl_msg *);
extern void idiagnl_msg_set_vegasinfo(struct idiagnl_msg *,
struct idiagnl_vegasinfo *);
extern struct tcp_info idiagnl_msg_get_tcpinfo(const struct idiagnl_msg *);
extern void idiagnl_msg_set_tcpinfo(struct idiagnl_msg *,
struct tcp_info *);
extern int idiagnl_msg_parse(struct nlmsghdr *,
struct idiagnl_msg **);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* NETLINK_IDIAGNL_MSG_H_ */

View File

@ -0,0 +1,50 @@
/*
* netlink/idiag/req.h Inetdiag Netlink Request
*
* 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) 2013 Sassano Systems LLC <joe@sassanosystems.com>
*/
#ifndef NETLINK_IDIAGNL_REQ_H_
#define NETLINK_IDIAGNL_REQ_H_
#include <netlink/netlink.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
struct idiagnl_req;
extern struct nl_object_ops idiagnl_req_obj_ops;
extern struct idiagnl_req * idiagnl_req_alloc(void);
extern void idiagnl_req_get(struct idiagnl_req *);
extern void idiagnl_req_put(struct idiagnl_req *);
extern uint8_t idiagnl_req_get_family(const struct idiagnl_req *);
extern void idiagnl_req_set_family(struct idiagnl_req *,
uint8_t);
extern uint8_t idiagnl_req_get_ext(const struct idiagnl_req *);
extern void idiagnl_req_set_ext(struct idiagnl_req *, uint8_t);
extern uint32_t idiagnl_req_get_ifindex(const struct idiagnl_req *);
extern void idiagnl_req_set_ifindex(struct idiagnl_req *,
uint32_t);
extern uint32_t idiagnl_req_get_states(const struct idiagnl_req *);
extern void idiagnl_req_set_states(struct idiagnl_req *,
uint32_t);
extern uint32_t idiagnl_req_get_dbs(const struct idiagnl_req *);
extern void idiagnl_req_set_dbs(struct idiagnl_req *, uint32_t);
extern struct nl_addr * idiagnl_req_get_src(const struct idiagnl_req *);
extern int idiagnl_req_set_src(struct idiagnl_req *,
struct nl_addr *);
extern struct nl_addr * idiagnl_req_get_dst(const struct idiagnl_req *);
extern int idiagnl_req_set_dst(struct idiagnl_req *,
struct nl_addr *);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* NETLINK_IDIAGNL_REQ_H_ */

View File

@ -0,0 +1,43 @@
/*
* netlink/idiag/vegasinfo.h Inetdiag Netlink TCP Vegas Info
*
* 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) 2013 Sassano Systems LLC <joe@sassanosystems.com>
*/
#ifndef NETLINK_IDIAGNL_VEGASINFO_H_
#define NETLINK_IDIAGNL_VEGASINFO_H_
#include <netlink/netlink.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
extern struct nl_object_ops idiagnl_vegasinfo_obj_ops;
extern struct idiagnl_vegasinfo * idiagnl_vegasinfo_alloc(void);
extern void idiagnl_vegasinfo_get(struct idiagnl_vegasinfo *);
extern void idiagnl_vegasinfo_put(struct idiagnl_vegasinfo *);
extern uint32_t idiagnl_vegasinfo_get_enabled(const struct idiagnl_vegasinfo *);
extern uint32_t idiagnl_vegasinfo_get_rttcnt(const struct idiagnl_vegasinfo *);
extern uint32_t idiagnl_vegasinfo_get_rtt(const struct idiagnl_vegasinfo *);
extern uint32_t idiagnl_vegasinfo_get_minrtt(const struct idiagnl_vegasinfo *);
extern void idiagnl_vegasinfo_set_enabled(struct idiagnl_vegasinfo *,
uint32_t);
extern void idiagnl_vegasinfo_set_rttcnt(struct idiagnl_vegasinfo *,
uint32_t);
extern void idiagnl_vegasinfo_set_rtt(struct idiagnl_vegasinfo *, uint32_t);
extern void idiagnl_vegasinfo_set_minrtt(struct idiagnl_vegasinfo *,
uint32_t);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* NETLINK_IDIAGNL_VEGASINFO_H_ */

View File

@ -26,6 +26,7 @@
#include <linux/rtnetlink.h>
#include <linux/genetlink.h>
#include <linux/netfilter/nfnetlink.h>
#include <netinet/tcp.h>
#include <netlink/version.h>
#include <netlink/errno.h>
#include <netlink/types.h>

View File

@ -13,13 +13,18 @@ AM_LDFLAGS = \
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
lib_LTLIBRARIES = \
libnl-3.la libnl-genl-3.la libnl-route-3.la libnl-nf-3.la
libnl-3.la libnl-genl-3.la libnl-route-3.la libnl-nf-3.la libnl-idiag-3.la
libnl_3_la_SOURCES = \
addr.c attr.c cache.c cache_mngr.c cache_mngt.c data.c \
error.c handlers.c msg.c nl.c object.c socket.c utils.c \
version.c hash.c hashtable.c
libnl_idiag_3_la_LIBADD = libnl-3.la
libnl_idiag_3_la_SOURCES = \
idiag/idiag_meminfo_obj.c idiag/idiag_vegasinfo_obj.c \
idiag/idiag_msg_obj.c idiag/idiag_req_obj.c idiag/idiag.c
libnl_genl_3_la_LIBADD = libnl-3.la
libnl_genl_3_la_SOURCES = \
genl/ctrl.c genl/family.c genl/genl.c genl/mngt.c

274
lib/idiag/idiag.c Normal file
View File

@ -0,0 +1,274 @@
/*
* lib/idiag/idiag.c Inet Diag Netlink
*
* 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) 2013 Sassano Systems LLC <joe@sassanosystems.com>
*/
/**
* @defgroup idiag Inet Diag library (libnl-idiag)
* @brief
* @{
*/
#include <netlink-private/netlink.h>
#include <netlink/netlink.h>
#include <netlink/cache.h>
#include <netlink/idiag/idiagnl.h>
#include <linux/inet_diag.h>
/**
* @name Socket Creation
* @{
*/
/**
* Create and connect idiag netlink socket.
* @arg sk Netlink socket.
*
* Creates a NETLINK_INET_DIAG socket, binds the socket, and issues a connection
* attemp.
*
* @see nl_connect()
*
* @return 0 on success or a negative error code.
*/
int idiagnl_connect(struct nl_sock *sk)
{
return nl_connect(sk, NETLINK_INET_DIAG);
}
/** @} */
/**
* @name Sending
* @{
*/
/**
* Send trivial idiag netlink message
* @arg sk Netlink socket.
* @arg flags Message flags
* @arg family Address family
* @arg states Socket states to query
* @arg ext Inet Diag attribute extensions to query
*
* @return Newly allocated netlink message or NULL.
*/
int idiagnl_send_simple(struct nl_sock *sk, int flags, uint8_t family,
uint16_t states, uint16_t ext)
{
struct inet_diag_req req;
memset(&req, 0, sizeof(req));
flags |= NLM_F_ROOT;
req.idiag_family = family;
req.idiag_states = states;
req.idiag_ext = ext;
return nl_send_simple(sk, TCPDIAG_GETSOCK, flags, &req, sizeof(req));
}
/** @} */
/**
* @name Inet Diag flag and attribute conversions
* @{
*/
static const struct trans_tbl idiag_states[] = {
__ADD(IDIAG_SS_UNKNOWN, unknown)
__ADD(IDIAG_SS_ESTABLISHED, established)
__ADD(IDIAG_SS_SYN_SENT, syn_sent)
__ADD(IDIAG_SS_SYN_RECV, syn_recv)
__ADD(IDIAG_SS_FIN_WAIT1, fin_wait)
__ADD(IDIAG_SS_FIN_WAIT2, fin_wait2)
__ADD(IDIAG_SS_TIME_WAIT, time_wait)
__ADD(IDIAG_SS_CLOSE, close)
__ADD(IDIAG_SS_CLOSE_WAIT, close_wait)
__ADD(IDIAG_SS_LAST_ACK, last_ack)
__ADD(IDIAG_SS_LISTEN, listen)
__ADD(IDIAG_SS_CLOSING, closing)
__ADD(IDIAG_SS_MAX, max)
{ ((1<<IDIAG_SS_MAX)-1), "all" }
};
/**
* Convert inet diag socket states to strings.
* @arg state inetdiag socket state (e.g., IDIAG_SS_ESTABLISHED)
* @arg buf output buffer which will hold string result
* @arg len length in bytes of the output buffer
*
* @return string representation of the inetdiag socket state or an empty
* string.
*/
char * idiagnl_state2str(int state, char *buf, size_t len)
{
return __type2str(state, buf, len, idiag_states,
ARRAY_SIZE(idiag_states));
}
/**
* Convert inet diag socket state string to int.
* @arg name inetdiag socket state string
*
* @return the int representation of the socket state strign or a negative error
* code.
*/
int idiagnl_str2state(const char *name)
{
return __str2type(name, idiag_states, ARRAY_SIZE(idiag_states));
}
static const struct trans_tbl idiag_timers[] = {
__ADD(IDIAG_TIMER_OFF, off)
__ADD(IDIAG_TIMER_ON, on)
__ADD(IDIAG_TIMER_KEEPALIVE, keepalive)
__ADD(IDIAG_TIMER_TIMEWAIT, timewait)
__ADD(IDIAG_TIMER_PERSIST, persist)
__ADD(IDIAG_TIMER_UNKNOWN, unknown)
};
/**
* Convert inet diag timer types to strings.
* @arg timer inetdiag timer (e.g., IDIAG_TIMER_ON)
* @arg buf output buffer which will hold string result
* @arg len length in bytes of the output buffer
*
* @return string representation of the inetdiag timer type or an empty string.
*/
char * idiagnl_timer2str(int timer, char *buf, size_t len)
{
return __type2str(timer, buf, len, idiag_timers,
ARRAY_SIZE(idiag_timers));
}
/**
* Convert inet diag timer string to int.
* @arg name inetdiag timer string
*
* @return the int representation of the timer string or a negative error code.
*/
int idiagnl_str2timer(const char *name)
{
return __str2type(name, idiag_timers, ARRAY_SIZE(idiag_timers));
}
static const struct trans_tbl idiag_attrs[] = {
__ADD(IDIAG_ATTR_NONE, none)
__ADD(IDIAG_ATTR_MEMINFO, meminfo)
__ADD(IDIAG_ATTR_INFO, info)
__ADD(IDIAG_ATTR_VEGASINFO, vegasinfo)
__ADD(IDIAG_ATTR_CONG, congestion)
__ADD(IDIAG_ATTR_TOS, tos)
__ADD(IDIAG_ATTR_TCLASS, tclass)
};
/**
* Convert inetdiag extended attributes to strings.
* @arg attrs inetdiag attribute (e.g., IDIAG_ATTR_MEMINFO)
* @arg buf output buffer which will hold string result
* @arg len length in bytes of the output buffer
*
* @return string representation of attrs or an empty string.
*/
char *idiagnl_attrs2str(int attrs, char *buf, size_t len)
{
return __type2str(attrs, buf, len, idiag_attrs, ARRAY_SIZE(idiag_attrs));
}
static const struct trans_tbl idiagnl_tcpstates[] = {
__ADD(TCP_CA_Open, open)
__ADD(TCP_CA_Disorder, disorder)
__ADD(TCP_CA_CWR, cwr)
__ADD(TCP_CA_Recovery, recovery)
__ADD(TCP_CA_Loss, loss)
};
/**
* Convert inetdiag tcp states to strings.
* @arg state TCP state (e.g., TCP_CA_Open)
* @arg buf output buffer which will hold string result
* @arg len length in bytes of the output buffer
*/
char *idiagnl_tcpstate2str(uint8_t state, char *buf, size_t len)
{
return __type2str(state, buf, len, idiagnl_tcpstates,
ARRAY_SIZE(idiagnl_tcpstates));
}
static const struct trans_tbl idiagnl_tcpopt_attrs[] = {
__ADD(TCPI_OPT_TIMESTAMPS, timestamps)
__ADD(TCPI_OPT_SACK, sACK)
__ADD(TCPI_OPT_WSCALE, wscale)
__ADD(TCPI_OPT_ECN, ecn)
};
/**
* Convert TCP option attributes to string
* @arg attrs TCP option attributes to convert (e.g., TCPI_OPT_SACK |
* TCPI_OPT_WSCALE)
* @arg buf Output buffer for string
* @arg len Length in bytes of output buffer
*
* @return buffer with string representation or empty string
*/
char *idiagnl_tcpopts2str(uint8_t attrs, char *buf, size_t len)
{
return __flags2str(attrs, buf, len, idiagnl_tcpopt_attrs,
ARRAY_SIZE(idiagnl_tcpopt_attrs));
}
/**
* Convert shutdown state to string.
* @arg shutdown Shutdown state (e.g., idiag_msg->shutdown)
* @arg buf Ouput buffer to hold string representation
* @arg len Length in bytes of output buffer
*
* @return string representation of shutdown state or NULL
*/
char * idiagnl_shutdown2str(uint8_t shutdown, char *buf, size_t len)
{
if (shutdown == 0) {
snprintf(buf, len, " ");
return buf;
} else if (shutdown == 1) {
snprintf(buf, len, "receive shutdown");
return buf;
} else if (shutdown == 2) {
snprintf(buf, len, "send shutdown");
return buf;
}
return NULL;
}
static const struct trans_tbl idiag_exts[] = {
__ADD(IDIAG_ATTR_NONE, none)
__ADD(IDIAG_ATTR_MEMINFO, meminfo)
__ADD(IDIAG_ATTR_INFO, info)
__ADD(IDIAG_ATTR_VEGASINFO, vegasinfo)
__ADD(IDIAG_ATTR_CONG, congestion)
__ADD(IDIAG_ATTR_TOS, tos)
__ADD(IDIAG_ATTR_TCLASS, tclass)
};
/**
* Convert inet diag extension flags to a string.
* @arg attrs inet diag extension flags (e.g., (IDIAG_ATTR_MEMINFO |
* IDIAG_ATTR_CONG | IDIAG_ATTR_TOS))
* @arg buf Output buffer to hold string representation
* @arg len length in bytes of the output buffer
*/
char *idiagnl_exts2str(uint8_t attrs, char *buf, size_t len)
{
return __flags2str(attrs, buf, len, idiag_exts, ARRAY_SIZE(idiag_exts));
}
/** @} */
/** @} */

View File

@ -0,0 +1,100 @@
/*
* lib/idiag/idiagnl_meminfo_obj.c Inet Diag Meminfo Object
*
* 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) 2013 Sassano Systems LLC <joe@sassanosystems.com>
*/
#include <netlink-private/netlink.h>
#include <netlink/idiag/meminfo.h>
/**
* @ingroup idiag
* @defgroup idiagnl_meminfo Inet Diag Memory Info
*
* @details
* @idiagnl_doc{idiagnl_meminfo, Inet Diag Memory Info Documentation}
* @{
*/
struct idiagnl_meminfo *idiagnl_meminfo_alloc(void)
{
return (struct idiagnl_meminfo *) nl_object_alloc(&idiagnl_meminfo_obj_ops);
}
void idiagnl_meminfo_get(struct idiagnl_meminfo *minfo)
{
nl_object_get((struct nl_object *) minfo);
}
void idiagnl_meminfo_put(struct idiagnl_meminfo *minfo)
{
nl_object_put((struct nl_object *) minfo);
}
/**
* @name Attributes
* @{
*/
uint32_t idiagnl_meminfo_get_rmem(const struct idiagnl_meminfo *minfo)
{
return minfo->idiag_rmem;
}
void idiagnl_meminfo_set_rmem(struct idiagnl_meminfo *minfo, uint32_t rmem)
{
minfo->idiag_rmem = rmem;
}
uint32_t idiagnl_meminfo_get_wmem(const struct idiagnl_meminfo *minfo)
{
return minfo->idiag_wmem;
}
void idiagnl_meminfo_set_wmem(struct idiagnl_meminfo *minfo, uint32_t wmem)
{
minfo->idiag_wmem = wmem;
}
uint32_t idiagnl_meminfo_get_fmem(const struct idiagnl_meminfo *minfo)
{
return minfo->idiag_fmem;
}
void idiagnl_meminfo_set_fmem(struct idiagnl_meminfo *minfo, uint32_t fmem)
{
minfo->idiag_fmem = fmem;
}
uint32_t idiagnl_meminfo_get_tmem(const struct idiagnl_meminfo *minfo)
{
return minfo->idiag_tmem;
}
void idiagnl_meminfo_set_tmem(struct idiagnl_meminfo *minfo, uint32_t tmem)
{
minfo->idiag_tmem = tmem;
}
/** @} */
static int idiagnl_meminfo_clone(struct nl_object *_dst, struct nl_object *_src)
{
struct idiagnl_meminfo *dst = (struct idiagnl_meminfo *) _dst;
struct idiagnl_meminfo *src = (struct idiagnl_meminfo *) _src;
memcpy(dst, src, sizeof(struct idiagnl_meminfo));
return 0;
}
/** @cond SKIP */
struct nl_object_ops idiagnl_meminfo_obj_ops = {
.oo_name = "idiag/idiag_meminfo",
.oo_size = sizeof(struct idiagnl_meminfo),
.oo_clone = idiagnl_meminfo_clone,
};
/** @endcond */
/** @} */

723
lib/idiag/idiag_msg_obj.c Normal file
View File

@ -0,0 +1,723 @@
/*
* lib/idiag/idiagnl_msg_obj.c Inet Diag Message Object
*
* 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) 2013 Sassano Systems LLC <joe@sassanosystems.com>
*/
#include <netlink-private/netlink.h>
#include <netlink/idiag/msg.h>
#include <netlink/idiag/meminfo.h>
#include <netlink/idiag/vegasinfo.h>
#include <linux/inet_diag.h>
/**
* @ingroup idiag
* @defgroup idiagnl_msg Inet Diag Messages
*
* @details
* @idiagnl_doc{idiagnl_msg, Inet Diag Message Documentation}
* @{
*/
struct idiagnl_msg *idiagnl_msg_alloc(void)
{
return (struct idiagnl_msg *) nl_object_alloc(&idiagnl_msg_obj_ops);
}
void idiagnl_msg_get(struct idiagnl_msg *msg)
{
nl_object_get((struct nl_object *) msg);
}
void idiagnl_msg_put(struct idiagnl_msg *msg)
{
nl_object_put((struct nl_object *) msg);
}
static struct nl_cache_ops idiagnl_msg_ops;
static int idiagnl_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
struct nlmsghdr *nlh, struct nl_parser_param *pp)
{
struct idiagnl_msg *msg = NULL;
int err = 0;
if ((err = idiagnl_msg_parse(nlh, &msg)) < 0)
return err;
err = pp->pp_cb((struct nl_object *) msg, pp);
idiagnl_msg_put(msg);
return err;
}
static int idiagnl_request_update(struct nl_cache *cache, struct nl_sock *sk)
{
int family = cache->c_iarg1;
int states = cache->c_iarg2;
return idiagnl_send_simple(sk, 0, family, states, IDIAG_ATTR_ALL);
}
static struct nl_cache_ops idiagnl_msg_ops = {
.co_name = "idiag/idiag",
.co_hdrsize = sizeof(struct inet_diag_msg),
.co_msgtypes = {
{ IDIAG_TCPDIAG_GETSOCK, NL_ACT_NEW, "new" },
{ IDIAG_DCCPDIAG_GETSOCK, NL_ACT_NEW, "new" },
END_OF_MSGTYPES_LIST,
},
.co_protocol = NETLINK_INET_DIAG,
.co_request_update = idiagnl_request_update,
.co_msg_parser = idiagnl_msg_parser,
.co_obj_ops = &idiagnl_msg_obj_ops,
};
static void __init idiagnl_init(void)
{
nl_cache_mngt_register(&idiagnl_msg_ops);
}
static void __exit idiagnl_exit(void)
{
nl_cache_mngt_unregister(&idiagnl_msg_ops);
}
/**
* @name Cache Management
* @{
*/
/**
* Build an inetdiag cache to hold socket state information.
* @arg sk Netlink socket
* @arg family The address family to query
* @arg states Socket states to query
* @arg result Result pointer
*
* @note The caller is responsible for destroying and free the cache after using
* it.
* @return 0 on success of a negative error code.
*/
int idiagnl_msg_alloc_cache(struct nl_sock *sk, int family, int states,
struct nl_cache **result)
{
struct nl_cache *cache = NULL;
int err;
if (!(cache = nl_cache_alloc(&idiagnl_msg_ops)))
return -NLE_NOMEM;
cache->c_iarg1 = family;
cache->c_iarg2 = states;
if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
free(cache);
return err;
}
*result = cache;
return 0;
}
/** @} */
/**
* @name Attributes
* @{
*/
uint8_t idiagnl_msg_get_family(const struct idiagnl_msg *msg)
{
return msg->idiag_family;
}
void idiagnl_msg_set_family(struct idiagnl_msg *msg, uint8_t family)
{
msg->idiag_family = family;
}
uint8_t idiagnl_msg_get_state(const struct idiagnl_msg *msg)
{
return msg->idiag_state;
}
void idiagnl_msg_set_state(struct idiagnl_msg *msg, uint8_t state)
{
msg->idiag_state = state;
}
uint8_t idiagnl_msg_get_timer(const struct idiagnl_msg *msg)
{
return msg->idiag_timer;
}
void idiagnl_msg_set_timer(struct idiagnl_msg *msg, uint8_t timer)
{
msg->idiag_timer = timer;
}
uint8_t idiagnl_msg_get_retrans(const struct idiagnl_msg *msg)
{
return msg->idiag_retrans;
}
void idiagnl_msg_set_retrans(struct idiagnl_msg *msg, uint8_t retrans)
{
msg->idiag_retrans = retrans;
}
uint16_t idiagnl_msg_get_sport(struct idiagnl_msg *msg)
{
return msg->idiag_sport;
}
void idiagnl_msg_set_sport(struct idiagnl_msg *msg, uint16_t port)
{
msg->idiag_sport = port;
}
uint16_t idiagnl_msg_get_dport(struct idiagnl_msg *msg)
{
return msg->idiag_dport;
}
void idiagnl_msg_set_dport(struct idiagnl_msg *msg, uint16_t port)
{
msg->idiag_dport = port;
}
struct nl_addr *idiagnl_msg_get_src(const struct idiagnl_msg *msg)
{
return msg->idiag_src;
}
int idiagnl_msg_set_src(struct idiagnl_msg *msg, struct nl_addr *addr)
{
if (msg->idiag_src)
nl_addr_put(msg->idiag_src);
nl_addr_get(addr);
msg->idiag_src = addr;
return 0;
}
struct nl_addr *idiagnl_msg_get_dst(const struct idiagnl_msg *msg)
{
return msg->idiag_dst;
}
int idiagnl_msg_set_dst(struct idiagnl_msg *msg, struct nl_addr *addr)
{
if (msg->idiag_dst)
nl_addr_put(msg->idiag_dst);
nl_addr_get(addr);
msg->idiag_dst = addr;
return 0;
}
uint32_t idiagnl_msg_get_ifindex(const struct idiagnl_msg *msg)
{
return msg->idiag_ifindex;
}
void idiagnl_msg_set_ifindex(struct idiagnl_msg *msg, uint32_t ifindex)
{
msg->idiag_ifindex = ifindex;
}
uint32_t idiagnl_msg_get_expires(const struct idiagnl_msg *msg)
{
return msg->idiag_expires;
}
void idiagnl_msg_set_expires(struct idiagnl_msg *msg, uint32_t expires)
{
msg->idiag_expires = expires;
}
uint32_t idiagnl_msg_get_rqueue(const struct idiagnl_msg *msg)
{
return msg->idiag_rqueue;
}
void idiagnl_msg_set_rqueue(struct idiagnl_msg *msg, uint32_t rqueue)
{
msg->idiag_rqueue = rqueue;
}
uint32_t idiagnl_msg_get_wqueue(const struct idiagnl_msg *msg)
{
return msg->idiag_wqueue;
}
void idiagnl_msg_set_wqueue(struct idiagnl_msg *msg, uint32_t wqueue)
{
msg->idiag_wqueue = wqueue;
}
uint32_t idiagnl_msg_get_uid(const struct idiagnl_msg *msg)
{
return msg->idiag_uid;
}
void idiagnl_msg_set_uid(struct idiagnl_msg *msg, uint32_t uid)
{
msg->idiag_uid = uid;
}
uint32_t idiagnl_msg_get_inode(const struct idiagnl_msg *msg)
{
return msg->idiag_inode;
}
void idiagnl_msg_set_inode(struct idiagnl_msg *msg, uint32_t inode)
{
msg->idiag_inode = inode;
}
uint8_t idiagnl_msg_get_tos(const struct idiagnl_msg *msg)
{
return msg->idiag_tos;
}
void idiagnl_msg_set_tos(struct idiagnl_msg *msg, uint8_t tos)
{
msg->idiag_tos = tos;
}
uint8_t idiagnl_msg_get_tclass(const struct idiagnl_msg *msg)
{
return msg->idiag_tclass;
}
void idiagnl_msg_set_tclass(struct idiagnl_msg *msg, uint8_t tclass)
{
msg->idiag_tclass = tclass;
}
uint8_t idiagnl_msg_get_shutdown(const struct idiagnl_msg *msg)
{
return msg->idiag_shutdown;
}
void idiagnl_msg_set_shutdown(struct idiagnl_msg *msg, uint8_t shutdown)
{
msg->idiag_shutdown = shutdown;
}
char *idiagnl_msg_get_cong(const struct idiagnl_msg *msg)
{
return msg->idiag_cong;
}
void idiagnl_msg_set_cong(struct idiagnl_msg *msg, char *cong)
{
msg->idiag_cong = strdup(cong);
}
struct idiagnl_meminfo *idiagnl_msg_get_meminfo(const struct idiagnl_msg *msg)
{
return msg->idiag_meminfo;
}
void idiagnl_msg_set_meminfo(struct idiagnl_msg *msg, struct idiagnl_meminfo
*minfo)
{
if (msg->idiag_meminfo)
idiagnl_meminfo_put(msg->idiag_meminfo);
idiagnl_meminfo_get(minfo);
msg->idiag_meminfo = minfo;
}
struct idiagnl_vegasinfo *idiagnl_msg_get_vegasinfo(const struct idiagnl_msg *msg)
{
return msg->idiag_vegasinfo;
}
void idiagnl_msg_set_vegasinfo(struct idiagnl_msg *msg, struct idiagnl_vegasinfo
*vinfo)
{
if (msg->idiag_vegasinfo)
idiagnl_vegasinfo_put(msg->idiag_vegasinfo);
idiagnl_vegasinfo_get(vinfo);
msg->idiag_vegasinfo = vinfo;
}
struct tcp_info idiagnl_msg_get_tcpinfo(const struct idiagnl_msg *msg)
{
return msg->idiag_tcpinfo;
}
void idiagnl_msg_set_tcpinfo(struct idiagnl_msg *msg, struct tcp_info *tinfo)
{
memcpy(&msg->idiag_tcpinfo, tinfo, sizeof(struct tcp_info));
}
/** @} */
static void idiag_msg_dump_line(struct nl_object *a, struct nl_dump_params *p)
{
struct idiagnl_msg *msg = (struct idiagnl_msg *) a;
char buf[64] = { 0 };
nl_dump_line(p, "family: %s ", nl_af2str(msg->idiag_family, buf, sizeof(buf)));
nl_dump(p, "src: %s:%d ", nl_addr2str(msg->idiag_src, buf, sizeof(buf)),
ntohs(msg->idiag_sport));
nl_dump(p, "dst: %s:%d ", nl_addr2str(msg->idiag_dst, buf, sizeof(buf)),
ntohs(msg->idiag_dport));
nl_dump(p, "iif: %d ", msg->idiag_ifindex);
nl_dump(p, "\n");
}
static void idiag_msg_dump_details(struct nl_object *a, struct nl_dump_params *p)
{
struct idiagnl_msg *msg = (struct idiagnl_msg *) a;
char buf[64], buf2[64];
nl_dump(p, "\nfamily: %s\n", nl_af2str(msg->idiag_family, buf, sizeof(buf)));
nl_dump(p, "state: %s\n",
idiagnl_state2str(msg->idiag_state, buf, sizeof(buf)));
nl_dump(p, "timer (%s, %s, retransmits: %d)\n",
idiagnl_timer2str(msg->idiag_timer, buf, sizeof(buf)),
nl_msec2str(msg->idiag_expires, buf2, sizeof(buf2)),
msg->idiag_retrans);
nl_dump(p, "source: %s:%d\n", nl_addr2str(msg->idiag_src, buf, sizeof(buf)),
ntohs(msg->idiag_sport));
nl_dump(p, "destination: %s:%d\n", nl_addr2str(msg->idiag_dst, buf, sizeof(buf)),
ntohs(msg->idiag_dport));
nl_dump(p, "ifindex: %d\n", msg->idiag_ifindex);
nl_dump(p, "rqueue: %-6d wqueue: %-6d\n", msg->idiag_rqueue, msg->idiag_wqueue);
nl_dump(p, "uid %d\n", msg->idiag_uid);
nl_dump(p, "inode %d\n", msg->idiag_inode);
if (msg->idiag_shutdown) {
nl_dump(p, "socket shutdown: %s\n",
idiagnl_shutdown2str(msg->idiag_shutdown,
buf, sizeof(buf)));
}
nl_dump(p, "tos: 0x%x\n", msg->idiag_tos);
nl_dump(p, "traffic class: %d\n", msg->idiag_tclass);
nl_dump(p, "congestion algorithm: %s\n", msg->idiag_cong);
}
static void idiag_msg_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
{
struct idiagnl_msg *msg = (struct idiagnl_msg *) obj;
char buf[64];
idiag_msg_dump_details(obj, p);
nl_dump(p, "tcp info: [\n");
nl_dump(p, "\tsocket state: %s\n",
idiagnl_state2str(msg->idiag_tcpinfo.tcpi_state,
buf, sizeof(buf)));
nl_dump(p, "\ttcp state: %s\n",
idiagnl_tcpstate2str(msg->idiag_tcpinfo.tcpi_ca_state,
buf, sizeof(buf)));
nl_dump(p, "\tretransmits: %d\n",
msg->idiag_tcpinfo.tcpi_retransmits);
nl_dump(p, "\tprobes: %d\n",
msg->idiag_tcpinfo.tcpi_probes);
nl_dump(p, "\tbackoff: %d\n",
msg->idiag_tcpinfo.tcpi_backoff);
nl_dump(p, "\toptions: %s\n",
idiagnl_tcpopts2str(msg->idiag_tcpinfo.tcpi_options,
buf, sizeof(buf)));
nl_dump(p, "\tsnd_wscale: %d\n", msg->idiag_tcpinfo.tcpi_snd_wscale);
nl_dump(p, "\trcv_wscale: %d\n", msg->idiag_tcpinfo.tcpi_rcv_wscale);
nl_dump(p, "\trto: %d\n", msg->idiag_tcpinfo.tcpi_rto);
nl_dump(p, "\tato: %d\n", msg->idiag_tcpinfo.tcpi_ato);
nl_dump(p, "\tsnd_mss: %s\n", nl_size2str(msg->idiag_tcpinfo.tcpi_snd_mss,
buf, sizeof(buf)));
nl_dump(p, "\trcv_mss: %s\n", nl_size2str(msg->idiag_tcpinfo.tcpi_rcv_mss,
buf, sizeof(buf)));
nl_dump(p, "\tunacked: %d\n", msg->idiag_tcpinfo.tcpi_unacked);
nl_dump(p, "\tsacked: %d\n", msg->idiag_tcpinfo.tcpi_sacked);
nl_dump(p, "\tlost: %d\n", msg->idiag_tcpinfo.tcpi_lost);
nl_dump(p, "\tretransmit segments: %d\n",
msg->idiag_tcpinfo.tcpi_retrans);
nl_dump(p, "\tfackets: %d\n",
msg->idiag_tcpinfo.tcpi_fackets);
nl_dump(p, "\tlast data sent: %s\n",
nl_msec2str(msg->idiag_tcpinfo.tcpi_last_data_sent, buf,
sizeof(buf)));
nl_dump(p, "\tlast ack sent: %s\n",
nl_msec2str(msg->idiag_tcpinfo.tcpi_last_ack_sent, buf, sizeof(buf)));
nl_dump(p, "\tlast data recv: %s\n",
nl_msec2str(msg->idiag_tcpinfo.tcpi_last_data_recv, buf,
sizeof(buf)));
nl_dump(p, "\tlast ack recv: %s\n",
nl_msec2str(msg->idiag_tcpinfo.tcpi_last_ack_recv, buf,
sizeof(buf)));
nl_dump(p, "\tpath mtu: %s\n",
nl_size2str(msg->idiag_tcpinfo.tcpi_pmtu, buf,
sizeof(buf)));
nl_dump(p, "\trcv ss threshold: %d\n",
msg->idiag_tcpinfo.tcpi_rcv_ssthresh);
nl_dump(p, "\tsmoothed round trip time: %d\n",
msg->idiag_tcpinfo.tcpi_rtt);
nl_dump(p, "\tround trip time variation: %d\n",
msg->idiag_tcpinfo.tcpi_rttvar);
nl_dump(p, "\tsnd ss threshold: %s\n",
nl_size2str(msg->idiag_tcpinfo.tcpi_snd_ssthresh, buf,
sizeof(buf)));
nl_dump(p, "\tsend congestion window: %d\n",
msg->idiag_tcpinfo.tcpi_snd_cwnd);
nl_dump(p, "\tadvertised mss: %s\n",
nl_size2str(msg->idiag_tcpinfo.tcpi_advmss, buf,
sizeof(buf)));
nl_dump(p, "\treordering: %d\n",
msg->idiag_tcpinfo.tcpi_reordering);
nl_dump(p, "\trcv rround trip time: %d\n",
msg->idiag_tcpinfo.tcpi_rcv_rtt);
nl_dump(p, "\treceive queue space: %s\n",
nl_size2str(msg->idiag_tcpinfo.tcpi_rcv_space, buf,
sizeof(buf)));
nl_dump(p, "\ttotal retransmits: %d\n",
msg->idiag_tcpinfo.tcpi_total_retrans);
nl_dump(p, "]\n");
if (msg->idiag_meminfo) {
nl_dump(p, "meminfo: [\n");
nl_dump(p, "\trmem: %s\n",
nl_size2str(msg->idiag_meminfo->idiag_rmem,
buf,
sizeof(buf)));
nl_dump(p, "\twmem: %s\n",
nl_size2str(msg->idiag_meminfo->idiag_wmem,
buf,
sizeof(buf)));
nl_dump(p, "\tfmem: %s\n",
nl_size2str(msg->idiag_meminfo->idiag_fmem,
buf,
sizeof(buf)));
nl_dump(p, "\ttmem: %s\n",
nl_size2str(msg->idiag_meminfo->idiag_tmem,
buf,
sizeof(buf)));
nl_dump(p, "]\n");
}
if (msg->idiag_vegasinfo) {
nl_dump(p, "vegasinfo: [\n");
nl_dump(p, "\tvegas enabled: %d\n",
msg->idiag_vegasinfo->tcpv_enabled);
if (msg->idiag_vegasinfo->tcpv_enabled) {
nl_dump(p, "\trtt cnt: %d",
msg->idiag_vegasinfo->tcpv_rttcnt);
nl_dump(p, "\trtt (propagation delay): %d",
msg->idiag_vegasinfo->tcpv_rtt);
nl_dump(p, "\tmin rtt: %d",
msg->idiag_vegasinfo->tcpv_minrtt);
}
nl_dump(p, "]\n");
}
nl_dump(p, "skmeminfo: [\n");
nl_dump(p, "\trmem alloc: %d\n",
msg->idiag_skmeminfo[IDIAG_SK_MEMINFO_RMEM_ALLOC]);
nl_dump(p, "\trcv buf: %s\n",
nl_size2str(msg->idiag_skmeminfo[IDIAG_SK_MEMINFO_RCVBUF],
buf, sizeof(buf)));
nl_dump(p, "\twmem alloc: %d\n",
msg->idiag_skmeminfo[IDIAG_SK_MEMINFO_WMEM_ALLOC]);
nl_dump(p, "\tsnd buf: %s\n",
nl_size2str(msg->idiag_skmeminfo[IDIAG_SK_MEMINFO_SNDBUF],
buf, sizeof(buf)));
nl_dump(p, "\tfwd alloc: %d\n",
msg->idiag_skmeminfo[IDIAG_SK_MEMINFO_FWD_ALLOC]);
nl_dump(p, "\twmem queued: %s\n",
nl_size2str(msg->idiag_skmeminfo[IDIAG_SK_MEMINFO_WMEM_QUEUED],
buf, sizeof(buf)));
nl_dump(p, "\topt mem: %d\n",
msg->idiag_skmeminfo[IDIAG_SK_MEMINFO_OPTMEM]);
nl_dump(p, "\tbacklog: %d\n",
msg->idiag_skmeminfo[IDIAG_SK_MEMINFO_BACKLOG]);
nl_dump(p, "]\n\n");
}
static void idiagnl_msg_free(struct nl_object *a)
{
struct idiagnl_msg *msg = (struct idiagnl_msg *) a;
if (a == NULL)
return;
free(msg->idiag_cong);
nl_addr_put(msg->idiag_src);
nl_addr_put(msg->idiag_dst);
idiagnl_meminfo_put(msg->idiag_meminfo);
idiagnl_vegasinfo_put(msg->idiag_vegasinfo);
}
static int idiagnl_msg_clone(struct nl_object *_dst, struct nl_object *_src)
{
struct idiagnl_msg *dst = (struct idiagnl_msg *) _dst;
struct idiagnl_msg *src = (struct idiagnl_msg *) _src;
if (src->idiag_src)
if (!(dst->idiag_src = nl_addr_clone(src->idiag_src)))
return -NLE_NOMEM;
if (src->idiag_dst)
if (!(dst->idiag_dst = nl_addr_clone(src->idiag_dst)))
return -NLE_NOMEM;
return 0;
}
static struct nla_policy ext_policy[IDIAG_ATTR_MAX] = {
[IDIAG_ATTR_MEMINFO] = { .minlen = sizeof(struct inet_diag_meminfo) },
[IDIAG_ATTR_INFO] = { .minlen = sizeof(struct tcp_info) },
[IDIAG_ATTR_VEGASINFO] = { .minlen = sizeof(struct tcpvegas_info) },
[IDIAG_ATTR_CONG] = { .type = NLA_STRING },
[IDIAG_ATTR_TOS] = { .type = NLA_U8 },
[IDIAG_ATTR_TCLASS] = { .type = NLA_U8 },
[IDIAG_ATTR_SKMEMINFO] = { .minlen = (sizeof(uint32_t) * IDIAG_SK_MEMINFO_VARS) },
[IDIAG_ATTR_SHUTDOWN] = { .type = NLA_U8 },
};
int idiagnl_msg_parse(struct nlmsghdr *nlh, struct idiagnl_msg **result)
{
struct idiagnl_msg *msg = NULL;
struct inet_diag_msg *raw_msg = NULL;
struct nl_addr *src = NULL, *dst = NULL;
struct nlattr *tb[IDIAG_ATTR_MAX];
int err = 0;
msg = idiagnl_msg_alloc();
if (!msg)
goto errout_nomem;
err = nlmsg_parse(nlh, sizeof(struct inet_diag_msg), tb, IDIAG_ATTR_MAX,
ext_policy);
if (err < 0)
goto errout;
raw_msg = nlmsg_data(nlh);
msg->idiag_family = raw_msg->idiag_family;
msg->idiag_state = raw_msg->idiag_state;
msg->idiag_timer = raw_msg->idiag_timer;
msg->idiag_retrans = raw_msg->idiag_retrans;
msg->idiag_expires = raw_msg->idiag_expires;
msg->idiag_rqueue = raw_msg->idiag_rqueue;
msg->idiag_wqueue = raw_msg->idiag_wqueue;
msg->idiag_uid = raw_msg->idiag_uid;
msg->idiag_inode = raw_msg->idiag_inode;
msg->idiag_sport = raw_msg->id.idiag_sport;
msg->idiag_dport = raw_msg->id.idiag_dport;
msg->idiag_ifindex = raw_msg->id.idiag_if;
dst = nl_addr_build(raw_msg->idiag_family, raw_msg->id.idiag_dst,
sizeof(raw_msg->id.idiag_dst));
if (!dst)
goto errout_nomem;
err = idiagnl_msg_set_dst(msg, dst);
if (err < 0)
goto errout;
nl_addr_put(dst);
src = nl_addr_build(raw_msg->idiag_family, raw_msg->id.idiag_src,
sizeof(raw_msg->id.idiag_src));
if (!src)
goto errout_nomem;
err = idiagnl_msg_set_src(msg, src);
if (err < 0)
goto errout;
nl_addr_put(src);
if (tb[IDIAG_ATTR_TOS])
msg->idiag_tos = nla_get_u8(tb[IDIAG_ATTR_TOS]);
if (tb[IDIAG_ATTR_TCLASS])
msg->idiag_tclass = nla_get_u8(tb[IDIAG_ATTR_TCLASS]);
if (tb[IDIAG_ATTR_SHUTDOWN])
msg->idiag_shutdown = nla_get_u8(tb[IDIAG_ATTR_SHUTDOWN]);
if (tb[IDIAG_ATTR_CONG])
msg->idiag_cong = nla_strdup(tb[IDIAG_ATTR_CONG]);
if (tb[IDIAG_ATTR_INFO])
nla_memcpy(&msg->idiag_tcpinfo, tb[IDIAG_ATTR_INFO],
sizeof(msg->idiag_tcpinfo));
if (tb[IDIAG_ATTR_MEMINFO]) {
msg->idiag_meminfo = idiagnl_meminfo_alloc();
if (!msg->idiag_meminfo)
goto errout_nomem;
/* This memcpy works only because struct idiagnl_meminfo lines
* up perfectly with inet_diag_meminfo.
*
* If you change one or the other, this must also change.
*/
nla_memcpy(msg->idiag_meminfo, tb[IDIAG_ATTR_MEMINFO],
sizeof(msg->idiag_meminfo));
idiagnl_meminfo_get(msg->idiag_meminfo);
}
if (tb[IDIAG_ATTR_VEGASINFO]) {
msg->idiag_vegasinfo = idiagnl_vegasinfo_alloc();
if (!msg->idiag_vegasinfo)
goto errout_nomem;
/* This memcpy works only because struct idiagnl_vegasinfo lines
* up perfectly with inet_diag_vegasinfo.
*
* If you change one or the other, this must also change.
*/
nla_memcpy(&msg->idiag_vegasinfo, tb[IDIAG_ATTR_VEGASINFO],
sizeof(msg->idiag_vegasinfo));
idiagnl_vegasinfo_get(msg->idiag_vegasinfo);
}
if (tb[IDIAG_ATTR_SKMEMINFO])
nla_memcpy(&msg->idiag_skmeminfo, tb[IDIAG_ATTR_SKMEMINFO],
sizeof(msg->idiag_skmeminfo));
*result = msg;
return 0;
errout:
idiagnl_msg_put(msg);
return err;
errout_nomem:
err = -NLE_NOMEM;
goto errout;
}
/** @cond SKIP */
struct nl_object_ops idiagnl_msg_obj_ops = {
.oo_name = "idiag/idiag_msg",
.oo_size = sizeof(struct idiagnl_msg),
.oo_free_data = idiagnl_msg_free,
.oo_clone = idiagnl_msg_clone,
.oo_dump = {
[NL_DUMP_LINE] = idiag_msg_dump_line,
[NL_DUMP_DETAILS] = idiag_msg_dump_details,
[NL_DUMP_STATS] = idiag_msg_dump_stats,
},
.oo_attrs2str = idiagnl_attrs2str,
.oo_id_attrs = (IDIAG_ATTR_INFO)
};
/** @endcond */
/** @} */

255
lib/idiag/idiag_req_obj.c Normal file
View File

@ -0,0 +1,255 @@
/*
* lib/idiag/idiagnl_req_obj.c Inet Diag Request Object
*
* 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) 2013 Sassano Systems LLC <joe@sassanosystems.com>
*/
#include <netlink-private/netlink.h>
#include <netlink/idiag/req.h>
#include <linux/inet_diag.h>
/**
* @ingroup idiag
* @defgroup idiagnl_req Inet Diag Requests
*
* @details
* @idiagnl_doc{idiagnl_req, Inet Diag Request Documentation}
* @{
*/
struct idiagnl_req *idiagnl_req_alloc(void)
{
return (struct idiagnl_req *) nl_object_alloc(&idiagnl_req_obj_ops);
}
void idiagnl_req_get(struct idiagnl_req *req)
{
nl_object_get((struct nl_object *) req);
}
void idiagnl_req_put(struct idiagnl_req *req)
{
nl_object_put((struct nl_object *) req);
}
/**
* @name Attributes
* @{
*/
uint8_t idiagnl_req_get_family(const struct idiagnl_req *req)
{
return req->idiag_family;
}
void idiagnl_req_set_family(struct idiagnl_req *req, uint8_t family)
{
req->idiag_family = family;
}
uint8_t idiagnl_req_get_ext(const struct idiagnl_req *req)
{
return req->idiag_ext;
}
void idiagnl_req_set_ext(struct idiagnl_req *req, uint8_t ext)
{
req->idiag_ext = ext;
}
uint32_t idiagnl_req_get_ifindex(const struct idiagnl_req *req)
{
return req->idiag_ifindex;
}
void idiagnl_req_set_ifindex(struct idiagnl_req *req, uint32_t ifindex)
{
req->idiag_states = ifindex;
}
uint32_t idiagnl_req_get_states(const struct idiagnl_req *req)
{
return req->idiag_states;
}
void idiagnl_req_set_states(struct idiagnl_req *req, uint32_t states)
{
req->idiag_states = states;
}
uint32_t idiagnl_req_get_dbs(const struct idiagnl_req *req)
{
return req->idiag_dbs;
}
void idiagnl_req_set_dbs(struct idiagnl_req *req, uint32_t dbs)
{
req->idiag_dbs = dbs;
}
struct nl_addr *idiagnl_req_get_src(const struct idiagnl_req *req)
{
return req->idiag_src;
}
int idiagnl_req_set_src(struct idiagnl_req *req, struct nl_addr *addr)
{
if (req->idiag_src)
nl_addr_put(req->idiag_src);
nl_addr_get(addr);
req->idiag_src = addr;
return 0;
}
struct nl_addr *idiagnl_req_get_dst(const struct idiagnl_req *req)
{
return req->idiag_dst;
}
int idiagnl_req_set_dst(struct idiagnl_req *req, struct nl_addr *addr)
{
if (req->idiag_dst)
nl_addr_put(req->idiag_dst);
nl_addr_get(addr);
req->idiag_dst = addr;
return 0;
}
/** @} */
static void idiag_req_dump_line(struct nl_object *a, struct nl_dump_params *p)
{
struct idiagnl_req *req = (struct idiagnl_req *) a;
char buf[64] = { 0 };
nl_dump_line(p, "%s ", nl_af2str(req->idiag_family, buf, sizeof(buf)));
nl_dump(p, "src %s ", nl_addr2str(req->idiag_src, buf, sizeof(buf)));
nl_dump(p, "dst %s ", nl_addr2str(req->idiag_dst, buf, sizeof(buf)));
nl_dump(p, "iif %d ", req->idiag_ifindex);
nl_dump(p, "\n");
}
static void idiag_req_dump_details(struct nl_object *a, struct nl_dump_params *p)
{
struct idiagnl_req *req = (struct idiagnl_req *) a;
char buf[64];
nl_dump_line(p, " ");
nl_dump(p, "%s ", nl_af2str(req->idiag_family, buf, sizeof(buf)));
nl_dump(p, "exts %s ",
idiagnl_exts2str(req->idiag_ext, buf, sizeof(buf)));
nl_dump(p, "src %s ", nl_addr2str(req->idiag_src, buf, sizeof(buf)));
nl_dump(p, "dst %s ", nl_addr2str(req->idiag_dst, buf, sizeof(buf)));
nl_dump(p, "iif %d ", req->idiag_ifindex);
nl_dump(p, "states %s ", idiagnl_state2str(req->idiag_states, buf,
sizeof(buf)));
nl_dump(p, "dbs %d", req->idiag_dbs);
nl_dump(p, "\n");
}
static void idiag_req_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
{
idiag_req_dump_details(obj, p);
}
static void idiagnl_req_free(struct nl_object *a)
{
struct idiagnl_req *req = (struct idiagnl_req *) a;
if (a == NULL)
return;
nl_addr_put(req->idiag_src);
nl_addr_put(req->idiag_dst);
}
static int idiagnl_req_clone(struct nl_object *_dst, struct nl_object *_src)
{
struct idiagnl_req *dst = (struct idiagnl_req *) _dst;
struct idiagnl_req *src = (struct idiagnl_req *) _src;
if (src->idiag_src)
if (!(dst->idiag_src = nl_addr_clone(src->idiag_src)))
return -NLE_NOMEM;
if (src->idiag_dst)
if (!(dst->idiag_dst = nl_addr_clone(src->idiag_dst)))
return -NLE_NOMEM;
return 0;
}
int idiagnl_req_parse(struct nlmsghdr *nlh, struct idiagnl_req **result)
{
struct idiagnl_req *req = NULL;
struct inet_diag_req *raw_req = NULL;
struct nl_addr *src = NULL, *dst = NULL;
int err = 0;
req = idiagnl_req_alloc();
if (!req)
goto errout_nomem;
raw_req = nlmsg_data(nlh);
req->idiag_family = raw_req->idiag_family;
req->idiag_ext = raw_req->idiag_ext;
req->idiag_states = raw_req->idiag_states;
req->idiag_dbs = raw_req->idiag_dbs;
req->idiag_ifindex = raw_req->id.idiag_if;
dst = nl_addr_build(raw_req->idiag_family, raw_req->id.idiag_dst,
sizeof(raw_req->id.idiag_dst));
if (!dst)
goto errout_nomem;
err = idiagnl_req_set_dst(req, dst);
if (err < 0)
goto errout;
nl_addr_put(dst);
src = nl_addr_build(raw_req->idiag_family, raw_req->id.idiag_src,
sizeof(raw_req->id.idiag_src));
if (!src)
goto errout_nomem;
err = idiagnl_req_set_src(req, src);
if (err < 0)
goto errout;
nl_addr_put(src);
*result = req;
return 0;
errout:
idiagnl_req_put(req);
return err;
errout_nomem:
err = -NLE_NOMEM;
goto errout;
}
/** @cond SKIP */
struct nl_object_ops idiagnl_req_obj_ops = {
.oo_name = "idiag/idiag_req",
.oo_size = sizeof(struct idiagnl_req),
.oo_free_data = idiagnl_req_free,
.oo_clone = idiagnl_req_clone,
.oo_dump = {
[NL_DUMP_LINE] = idiag_req_dump_line,
[NL_DUMP_DETAILS] = idiag_req_dump_details,
[NL_DUMP_STATS] = idiag_req_dump_stats,
},
};
/** @endcond */
/** @} */

View File

@ -0,0 +1,104 @@
/*
* lib/idiag/idiagnl_vegasinfo_obj.c Inet Diag TCP Vegas Info Object
*
* 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) 2013 Sassano Systems LLC <joe@sassanosystems.com>
*/
#include <netlink-private/netlink.h>
#include <netlink/idiag/vegasinfo.h>
/**
* @ingroup idiag
* @defgroup idiagnl_vegasinfo Inet Diag TCP Vegas Info
*
* @details
* @idiagnl_doc{idiagnl_vegasinfo, Inet Diag TCP Vegas Info Documentation}
* @{
*/
struct idiagnl_vegasinfo *idiagnl_vegasinfo_alloc(void)
{
return (struct idiagnl_vegasinfo *) nl_object_alloc(&idiagnl_vegasinfo_obj_ops);
}
void idiagnl_vegasinfo_get(struct idiagnl_vegasinfo *vinfo)
{
nl_object_get((struct nl_object *) vinfo);
}
void idiagnl_vegasinfo_put(struct idiagnl_vegasinfo *vinfo)
{
nl_object_put((struct nl_object *) vinfo);
}
/**
* @name Attributes
* @{
*/
uint32_t idiagnl_vegasinfo_get_enabled(const struct idiagnl_vegasinfo *vinfo)
{
return vinfo->tcpv_enabled;
}
void idiagnl_vegasinfo_set_enabled(struct idiagnl_vegasinfo *vinfo, uint32_t
enabled)
{
vinfo->tcpv_enabled = enabled;
}
uint32_t idiagnl_vegasinfo_get_rttcnt(const struct idiagnl_vegasinfo *vinfo)
{
return vinfo->tcpv_rttcnt;
}
void idiagnl_vegasinfo_set_rttcnt(struct idiagnl_vegasinfo *vinfo, uint32_t
rttcnt)
{
vinfo->tcpv_rttcnt = rttcnt;
}
uint32_t idiagnl_vegasinfo_get_rtt(const struct idiagnl_vegasinfo *vinfo)
{
return vinfo->tcpv_rtt;
}
void idiagnl_vegasinfo_set_rtt(struct idiagnl_vegasinfo *vinfo, uint32_t rtt)
{
vinfo->tcpv_rtt = rtt;
}
uint32_t idiagnl_vegasinfo_get_minrtt(const struct idiagnl_vegasinfo *vinfo)
{
return vinfo->tcpv_minrtt;
}
void idiagnl_vegasinfo_set_minrtt(struct idiagnl_vegasinfo *vinfo, uint32_t
minrtt)
{
vinfo->tcpv_minrtt = minrtt;
}
/** @} */
static int idiagnl_vegasinfo_clone(struct nl_object *_dst,
struct nl_object *_src)
{
struct idiagnl_vegasinfo *dst = (struct idiagnl_vegasinfo *) _dst;
struct idiagnl_vegasinfo *src = (struct idiagnl_vegasinfo *) _src;
memcpy(dst, src, sizeof(struct idiagnl_vegasinfo));
return 0;
}
/** @cond SKIP */
struct nl_object_ops idiagnl_vegasinfo_obj_ops = {
.oo_name = "idiag/idiag_vegasinfo",
.oo_size = sizeof(struct idiagnl_vegasinfo),
.oo_clone = idiagnl_vegasinfo_clone,
};
/** @endcond */
/** @} */

View File

@ -998,7 +998,7 @@ char *__flags2str(int flags, char *buf, size_t len,
int tmp = flags;
memset(buf, 0, len);
for (i = 0; i < tbl_len; i++) {
if (tbl[i].i & tmp) {
tmp &= ~tbl[i].i;

12
libnl-idiag-3.0.pc.in Normal file
View File

@ -0,0 +1,12 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libnl-idiag
Description: Netlink Inet Diag Family Library
Version: @PACKAGE_VERSION@
Requires: libnl-3.0
Libs: -L${libdir} -lnl-idiag-@MAJ_VERSION@
Cflags: -I${includedir}/libnl@MAJ_VERSION@

View File

@ -9,7 +9,8 @@ LDADD = \
${top_builddir}/lib/libnl-3.la \
${top_builddir}/lib/libnl-nf-3.la \
${top_builddir}/lib/libnl-genl-3.la \
${top_builddir}/lib/libnl-route-3.la
${top_builddir}/lib/libnl-route-3.la \
${top_builddir}/lib/libnl-idiag-3.la
sbin_PROGRAMS = \
genl-ctrl-list \