diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in
index 7a0640c..50e8f0c 100644
--- a/doc/Doxyfile.in
+++ b/doc/Doxyfile.in
@@ -197,8 +197,10 @@ ALIASES = arg=\param \
"ref_asciidoc{3}=\3" \
"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"
diff --git a/include/Makefile.am b/include/Makefile.am
index 776323c..6f2f6d8 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -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 += \
diff --git a/include/netlink-private/types.h b/include/netlink-private/types.h
index 89f6418..60b880d 100644
--- a/include/netlink-private/types.h
+++ b/include/netlink-private/types.h
@@ -7,6 +7,7 @@
* of the License.
*
* Copyright (c) 2003-2013 Thomas Graf
+ * Copyright (c) 2013 Sassano Systems LLC
*/
#ifndef NETLINK_LOCAL_TYPES_H_
@@ -17,6 +18,7 @@
#include
#include
#include
+#include
#include
#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
diff --git a/include/netlink/idiag/idiagnl.h b/include/netlink/idiag/idiagnl.h
new file mode 100644
index 0000000..d7434cd
--- /dev/null
+++ b/include/netlink/idiag/idiagnl.h
@@ -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
+ */
+
+#ifndef NETLINK_IDIAGNL_H_
+#define NETLINK_IDIAGNL_H_
+
+#include
+
+#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<
+ */
+
+#ifndef NETLINK_IDIAGNL_MEMINFO_H_
+#define NETLINK_IDIAGNL_MEMINFO_H_
+
+#include
+
+#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_ */
diff --git a/include/netlink/idiag/msg.h b/include/netlink/idiag/msg.h
new file mode 100644
index 0000000..4aae606
--- /dev/null
+++ b/include/netlink/idiag/msg.h
@@ -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
+ */
+
+#ifndef NETLINK_IDIAGNL_MSG_H_
+#define NETLINK_IDIAGNL_MSG_H_
+
+#include
+
+#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_ */
diff --git a/include/netlink/idiag/req.h b/include/netlink/idiag/req.h
new file mode 100644
index 0000000..3c9f8ac
--- /dev/null
+++ b/include/netlink/idiag/req.h
@@ -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
+ */
+
+#ifndef NETLINK_IDIAGNL_REQ_H_
+#define NETLINK_IDIAGNL_REQ_H_
+
+#include
+
+#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_ */
diff --git a/include/netlink/idiag/vegasinfo.h b/include/netlink/idiag/vegasinfo.h
new file mode 100644
index 0000000..792b5c1
--- /dev/null
+++ b/include/netlink/idiag/vegasinfo.h
@@ -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
+ */
+
+#ifndef NETLINK_IDIAGNL_VEGASINFO_H_
+#define NETLINK_IDIAGNL_VEGASINFO_H_
+
+#include
+
+#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_ */
diff --git a/include/netlink/netlink.h b/include/netlink/netlink.h
index 1d74ba1..28dba06 100644
--- a/include/netlink/netlink.h
+++ b/include/netlink/netlink.h
@@ -26,6 +26,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 0376cbb..a6aa06d 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -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
diff --git a/lib/idiag/idiag.c b/lib/idiag/idiag.c
new file mode 100644
index 0000000..81d73db
--- /dev/null
+++ b/lib/idiag/idiag.c
@@ -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
+ */
+
+/**
+ * @defgroup idiag Inet Diag library (libnl-idiag)
+ * @brief
+ * @{
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+/**
+ * @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<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));
+}
+
+/** @} */
+/** @} */
diff --git a/lib/idiag/idiag_meminfo_obj.c b/lib/idiag/idiag_meminfo_obj.c
new file mode 100644
index 0000000..a60f497
--- /dev/null
+++ b/lib/idiag/idiag_meminfo_obj.c
@@ -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
+ */
+
+#include
+#include
+
+/**
+ * @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 */
+/** @} */
diff --git a/lib/idiag/idiag_msg_obj.c b/lib/idiag/idiag_msg_obj.c
new file mode 100644
index 0000000..707868a
--- /dev/null
+++ b/lib/idiag/idiag_msg_obj.c
@@ -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
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+/**
+ * @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 */
+
+/** @} */
diff --git a/lib/idiag/idiag_req_obj.c b/lib/idiag/idiag_req_obj.c
new file mode 100644
index 0000000..d9dab8e
--- /dev/null
+++ b/lib/idiag/idiag_req_obj.c
@@ -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
+ */
+
+#include
+#include
+#include
+
+/**
+ * @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 */
+
+/** @} */
diff --git a/lib/idiag/idiag_vegasinfo_obj.c b/lib/idiag/idiag_vegasinfo_obj.c
new file mode 100644
index 0000000..5279e83
--- /dev/null
+++ b/lib/idiag/idiag_vegasinfo_obj.c
@@ -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
+ */
+
+#include
+#include
+
+/**
+ * @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 */
+/** @} */
diff --git a/lib/utils.c b/lib/utils.c
index e491177..234e0de 100644
--- a/lib/utils.c
+++ b/lib/utils.c
@@ -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;
diff --git a/libnl-idiag-3.0.pc.in b/libnl-idiag-3.0.pc.in
new file mode 100644
index 0000000..9ce5100
--- /dev/null
+++ b/libnl-idiag-3.0.pc.in
@@ -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@
+
diff --git a/src/Makefile.am b/src/Makefile.am
index c318dcc..6541f6d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -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 \