]> granicus.if.org Git - libnl/commitdiff
Add support for inet diag Netlink protocol.
authorJoe Damato <ice799@gmail.com>
Thu, 4 Jul 2013 01:40:58 +0000 (18:40 -0700)
committerJoe Damato <ice799@gmail.com>
Fri, 19 Jul 2013 09:06:21 +0000 (02:06 -0700)
- 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.

18 files changed:
doc/Doxyfile.in
include/Makefile.am
include/netlink-private/types.h
include/netlink/idiag/idiagnl.h [new file with mode: 0644]
include/netlink/idiag/meminfo.h [new file with mode: 0644]
include/netlink/idiag/msg.h [new file with mode: 0644]
include/netlink/idiag/req.h [new file with mode: 0644]
include/netlink/idiag/vegasinfo.h [new file with mode: 0644]
include/netlink/netlink.h
lib/Makefile.am
lib/idiag/idiag.c [new file with mode: 0644]
lib/idiag/idiag_meminfo_obj.c [new file with mode: 0644]
lib/idiag/idiag_msg_obj.c [new file with mode: 0644]
lib/idiag/idiag_req_obj.c [new file with mode: 0644]
lib/idiag/idiag_vegasinfo_obj.c [new file with mode: 0644]
lib/utils.c
libnl-idiag-3.0.pc.in [new file with mode: 0644]
src/Makefile.am

index 7a0640c0cb15c2ba6b4013ec0478c9f268f75295..50e8f0c9fe7786693df0c99cc503453b226a0f27 100644 (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"
 
index 776323c2203856efa47fe8dbc35db3d5f7f64580..6f2f6d898f334e7c639b211b855de0417c287851 100644 (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 += \
index 89f6418bebd14dcd48d5fbfa1dc43c417eb645da..60b880d13d05891480fb5d01b2961a438a8fea8e 100644 (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
diff --git a/include/netlink/idiag/idiagnl.h b/include/netlink/idiag/idiagnl.h
new file mode 100644 (file)
index 0000000..d7434cd
--- /dev/null
@@ -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_ */
diff --git a/include/netlink/idiag/meminfo.h b/include/netlink/idiag/meminfo.h
new file mode 100644 (file)
index 0000000..1922395
--- /dev/null
@@ -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_ */
diff --git a/include/netlink/idiag/msg.h b/include/netlink/idiag/msg.h
new file mode 100644 (file)
index 0000000..4aae606
--- /dev/null
@@ -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_ */
diff --git a/include/netlink/idiag/req.h b/include/netlink/idiag/req.h
new file mode 100644 (file)
index 0000000..3c9f8ac
--- /dev/null
@@ -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_ */
diff --git a/include/netlink/idiag/vegasinfo.h b/include/netlink/idiag/vegasinfo.h
new file mode 100644 (file)
index 0000000..792b5c1
--- /dev/null
@@ -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_ */
index 1d74ba13a721152f8a594f32fa7748ed5906a5e8..28dba06edd56cfcc18811c43680ebb13ce038807 100644 (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>
index 0376cbb1f8a0d64126ec0d141383c0febe9690d6..a6aa06d52ee6209abeada5fda54425341bdefa1d 100644 (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
diff --git a/lib/idiag/idiag.c b/lib/idiag/idiag.c
new file mode 100644 (file)
index 0000000..81d73db
--- /dev/null
@@ -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));
+}
+
+/** @} */
+/** @} */
diff --git a/lib/idiag/idiag_meminfo_obj.c b/lib/idiag/idiag_meminfo_obj.c
new file mode 100644 (file)
index 0000000..a60f497
--- /dev/null
@@ -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 */
+/** @} */
diff --git a/lib/idiag/idiag_msg_obj.c b/lib/idiag/idiag_msg_obj.c
new file mode 100644 (file)
index 0000000..707868a
--- /dev/null
@@ -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 */
+
+/** @} */
diff --git a/lib/idiag/idiag_req_obj.c b/lib/idiag/idiag_req_obj.c
new file mode 100644 (file)
index 0000000..d9dab8e
--- /dev/null
@@ -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 */
+
+/** @} */
diff --git a/lib/idiag/idiag_vegasinfo_obj.c b/lib/idiag/idiag_vegasinfo_obj.c
new file mode 100644 (file)
index 0000000..5279e83
--- /dev/null
@@ -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 */
+/** @} */
index e491177d13bb2b6a2e1e7ece8317cbfa03012f6a..234e0defd0a349c03a71e90e2025e0d947e925fb 100644 (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;
diff --git a/libnl-idiag-3.0.pc.in b/libnl-idiag-3.0.pc.in
new file mode 100644 (file)
index 0000000..9ce5100
--- /dev/null
@@ -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@
+
index c318dccc2560c02ce6743a976c340836ca831fd3..6541f6dc4db0539402531195a4d1abffcb63ea50 100644 (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 \