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 \