From a3c0c04eff814ad6b6a4b17cad4d6a17361ad617 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 24 Nov 2014 17:14:45 +0100 Subject: [PATCH 01/13] idiag: add copy of kernel header include/linux/inet_diag.h Taken from upstream kernel commit bfe01a5ba2490f299e1d2d5508cbbbadd897bbe9 (v3.17), file 'include/uapi/linux/inet_diag.h'. Acked-by: Thomas Graf Signed-off-by: Thomas Haller --- include/Makefile.am | 1 + include/linux-private/linux/inet_diag.h | 137 ++++++++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 include/linux-private/linux/inet_diag.h diff --git a/include/Makefile.am b/include/Makefile.am index d5ce186..a56b227 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -131,6 +131,7 @@ noinst_HEADERS = \ linux-private/linux/if_link.h \ linux-private/linux/if_tunnel.h \ linux-private/linux/if_vlan.h \ + linux-private/linux/inet_diag.h \ linux-private/linux/ip.h \ linux-private/linux/ip_mp_alg.h \ linux-private/linux/ipv6.h \ diff --git a/include/linux-private/linux/inet_diag.h b/include/linux-private/linux/inet_diag.h new file mode 100644 index 0000000..bbde90f --- /dev/null +++ b/include/linux-private/linux/inet_diag.h @@ -0,0 +1,137 @@ +#ifndef _UAPI_INET_DIAG_H_ +#define _UAPI_INET_DIAG_H_ + +#include + +/* Just some random number */ +#define TCPDIAG_GETSOCK 18 +#define DCCPDIAG_GETSOCK 19 + +#define INET_DIAG_GETSOCK_MAX 24 + +/* Socket identity */ +struct inet_diag_sockid { + __be16 idiag_sport; + __be16 idiag_dport; + __be32 idiag_src[4]; + __be32 idiag_dst[4]; + __u32 idiag_if; + __u32 idiag_cookie[2]; +#define INET_DIAG_NOCOOKIE (~0U) +}; + +/* Request structure */ + +struct inet_diag_req { + __u8 idiag_family; /* Family of addresses. */ + __u8 idiag_src_len; + __u8 idiag_dst_len; + __u8 idiag_ext; /* Query extended information */ + + struct inet_diag_sockid id; + + __u32 idiag_states; /* States to dump */ + __u32 idiag_dbs; /* Tables to dump (NI) */ +}; + +struct inet_diag_req_v2 { + __u8 sdiag_family; + __u8 sdiag_protocol; + __u8 idiag_ext; + __u8 pad; + __u32 idiag_states; + struct inet_diag_sockid id; +}; + +enum { + INET_DIAG_REQ_NONE, + INET_DIAG_REQ_BYTECODE, +}; + +#define INET_DIAG_REQ_MAX INET_DIAG_REQ_BYTECODE + +/* Bytecode is sequence of 4 byte commands followed by variable arguments. + * All the commands identified by "code" are conditional jumps forward: + * to offset cc+"yes" or to offset cc+"no". "yes" is supposed to be + * length of the command and its arguments. + */ + +struct inet_diag_bc_op { + unsigned char code; + unsigned char yes; + unsigned short no; +}; + +enum { + INET_DIAG_BC_NOP, + INET_DIAG_BC_JMP, + INET_DIAG_BC_S_GE, + INET_DIAG_BC_S_LE, + INET_DIAG_BC_D_GE, + INET_DIAG_BC_D_LE, + INET_DIAG_BC_AUTO, + INET_DIAG_BC_S_COND, + INET_DIAG_BC_D_COND, +}; + +struct inet_diag_hostcond { + __u8 family; + __u8 prefix_len; + int port; + __be32 addr[0]; +}; + +/* Base info structure. It contains socket identity (addrs/ports/cookie) + * and, alas, the information shown by netstat. */ +struct inet_diag_msg { + __u8 idiag_family; + __u8 idiag_state; + __u8 idiag_timer; + __u8 idiag_retrans; + + struct inet_diag_sockid id; + + __u32 idiag_expires; + __u32 idiag_rqueue; + __u32 idiag_wqueue; + __u32 idiag_uid; + __u32 idiag_inode; +}; + +/* Extensions */ + +enum { + INET_DIAG_NONE, + INET_DIAG_MEMINFO, + INET_DIAG_INFO, + INET_DIAG_VEGASINFO, + INET_DIAG_CONG, + INET_DIAG_TOS, + INET_DIAG_TCLASS, + INET_DIAG_SKMEMINFO, + INET_DIAG_SHUTDOWN, +}; + +#define INET_DIAG_MAX INET_DIAG_SHUTDOWN + + +/* INET_DIAG_MEM */ + +struct inet_diag_meminfo { + __u32 idiag_rmem; + __u32 idiag_wmem; + __u32 idiag_fmem; + __u32 idiag_tmem; +}; + +/* INET_DIAG_VEGASINFO */ + +struct tcpvegas_info { + __u32 tcpv_enabled; + __u32 tcpv_rttcnt; + __u32 tcpv_rtt; + __u32 tcpv_minrtt; +}; + + +#endif /* _UAPI_INET_DIAG_H_ */ From fffc7ecedd4bd5cacd6ba096e4619b84dd4f5991 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 24 Nov 2014 17:14:46 +0100 Subject: [PATCH 02/13] idiag: fix out of bound error parsing idiag messages Acked-by: Thomas Graf Signed-off-by: Thomas Haller --- lib/idiag/idiag_msg_obj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/idiag/idiag_msg_obj.c b/lib/idiag/idiag_msg_obj.c index f1b5e28..b6f55c8 100644 --- a/lib/idiag/idiag_msg_obj.c +++ b/lib/idiag/idiag_msg_obj.c @@ -603,7 +603,7 @@ int idiagnl_msg_parse(struct nlmsghdr *nlh, struct idiagnl_msg **result) if (!msg) goto errout_nomem; - err = nlmsg_parse(nlh, sizeof(struct inet_diag_msg), tb, IDIAG_ATTR_MAX, + err = nlmsg_parse(nlh, sizeof(struct inet_diag_msg), tb, IDIAG_ATTR_MAX - 1, ext_policy); if (err < 0) goto errout; From cd8cd2dae27c2b56464b166753716b2e3725375a Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 24 Nov 2014 17:14:47 +0100 Subject: [PATCH 03/13] idiag: deprecate idiagnl_msg_obj_ops variable in public API This internal structure should never have been exposed publically. It as introduced as public API in v3.2.23. For now, don't remove it as it would be an API/ABI break. Fixes: 81d2b1d509d91fe894e4aec0a6a76b0bf75514cd Acked-by: Thomas Graf Signed-off-by: Thomas Haller --- include/netlink/idiag/msg.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/netlink/idiag/msg.h b/include/netlink/idiag/msg.h index 4aae606..01e30db 100644 --- a/include/netlink/idiag/msg.h +++ b/include/netlink/idiag/msg.h @@ -19,6 +19,8 @@ extern "C" { #endif /* __cplusplus */ struct idiagnl_msg; + +/* @deprecated: DO NOT USE this variable. */ extern struct nl_object_ops idiagnl_msg_obj_ops; extern struct idiagnl_msg * idiagnl_msg_alloc(void); From 22eb2569a595be98ae09fc4192860c1d2c3aa54c Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 24 Nov 2014 17:14:48 +0100 Subject: [PATCH 04/13] idiag: deprecate IDIAG_ATTR_* enumeration IDIAG_ATTR_* were a copy of the INET_DIAG_* extension kernel flags. Redefining them is wrong, user space should continue to use the values provided via the kernel headers. Also they were misused as change flags (ce_mask), which they are not. Deprecate the IDIAG_ATTR_* flags and redefine them to what the originally are: INET_DIAG_*. Also deprecated idiagnl_attrs2str() because there is already idiagnl_exts2str(). idiagnl_attrs2str() in the sense of libnl change flags (ce_mask) makes no sense. Acked-by: Thomas Graf Signed-off-by: Thomas Haller --- include/netlink/idiag/idiagnl.h | 33 ++++++++--------- lib/idiag/idiag.c | 58 +++++++++++++----------------- lib/idiag/idiag_msg_obj.c | 63 ++++++++++++++++++--------------- 3 files changed, 76 insertions(+), 78 deletions(-) diff --git a/include/netlink/idiag/idiagnl.h b/include/netlink/idiag/idiagnl.h index 64bccd7..58fe82e 100644 --- a/include/netlink/idiag/idiagnl.h +++ b/include/netlink/idiag/idiagnl.h @@ -55,25 +55,26 @@ enum { /** * Inet Diag extended attributes * @ingroup idiag - */ + * @deprecated These attributes should not be used. They mirror the + * INET_DIAG_* extension flags from kernel headers. Use those instead. */ 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, + IDIAG_ATTR_NONE = 0, /* INET_DIAG_NONE */ + IDIAG_ATTR_MEMINFO = 1, /* INET_DIAG_MEMINFO */ + IDIAG_ATTR_INFO = 2, /* INET_DIAG_INFO */ + IDIAG_ATTR_VEGASINFO = 3, /* INET_DIAG_VEGASINFO */ + IDIAG_ATTR_CONG = 4, /* INET_DIAG_CONG */ + IDIAG_ATTR_TOS = 5, /* INET_DIAG_TOS */ + IDIAG_ATTR_TCLASS = 6, /* INET_DIAG_TCLASS */ + IDIAG_ATTR_SKMEMINFO = 7, /* INET_DIAG_SKMEMINFO */ + IDIAG_ATTR_SHUTDOWN = 8, /* INET_DIAG_SHUTDOWN */ + + /* IDIAG_ATTR_MAX was wrong, because it did not correspond to + * INET_DIAG_MAX. Anyway, freeze it to the previous value. */ + IDIAG_ATTR_MAX = 9, + + IDIAG_ATTR_ALL = (1< #include + +#define _INET_DIAG_ALL ((1<<(INET_DIAG_MAX+1))-1) + /** * @ingroup idiag * @defgroup idiagnl_msg Inet Diag Messages @@ -61,7 +64,7 @@ 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); + return idiagnl_send_simple(sk, 0, family, states, _INET_DIAG_ALL); } static struct nl_cache_ops idiagnl_msg_ops = { @@ -579,16 +582,16 @@ static int idiagnl_msg_clone(struct nl_object *_dst, struct nl_object *_src) 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 }, +static struct nla_policy ext_policy[INET_DIAG_MAX+1] = { + [INET_DIAG_MEMINFO] = { .minlen = sizeof(struct inet_diag_meminfo) }, + [INET_DIAG_INFO] = { .minlen = sizeof(struct tcp_info) }, + [INET_DIAG_VEGASINFO] = { .minlen = sizeof(struct tcpvegas_info) }, + [INET_DIAG_CONG] = { .type = NLA_STRING }, + [INET_DIAG_TOS] = { .type = NLA_U8 }, + [INET_DIAG_TCLASS] = { .type = NLA_U8 }, /* Older kernel doesn't have SK_MEMINFO_BACKLOG */ - [IDIAG_ATTR_SKMEMINFO] = { .minlen = (sizeof(uint32_t) * (SK_MEMINFO_OPTMEM + 1)) }, - [IDIAG_ATTR_SHUTDOWN] = { .type = NLA_U8 }, + [INET_DIAG_SKMEMINFO] = { .minlen = (sizeof(uint32_t) * (SK_MEMINFO_OPTMEM + 1)) }, + [INET_DIAG_SHUTDOWN] = { .type = NLA_U8 }, }; int idiagnl_msg_parse(struct nlmsghdr *nlh, struct idiagnl_msg **result) @@ -596,14 +599,14 @@ 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]; + struct nlattr *tb[INET_DIAG_MAX+1]; 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 - 1, + err = nlmsg_parse(nlh, sizeof(struct inet_diag_msg), tb, INET_DIAG_MAX, ext_policy); if (err < 0) goto errout; @@ -644,23 +647,23 @@ int idiagnl_msg_parse(struct nlmsghdr *nlh, struct idiagnl_msg **result) nl_addr_put(src); - if (tb[IDIAG_ATTR_TOS]) - msg->idiag_tos = nla_get_u8(tb[IDIAG_ATTR_TOS]); + if (tb[INET_DIAG_TOS]) + msg->idiag_tos = nla_get_u8(tb[INET_DIAG_TOS]); - if (tb[IDIAG_ATTR_TCLASS]) - msg->idiag_tclass = nla_get_u8(tb[IDIAG_ATTR_TCLASS]); + if (tb[INET_DIAG_TCLASS]) + msg->idiag_tclass = nla_get_u8(tb[INET_DIAG_TCLASS]); - if (tb[IDIAG_ATTR_SHUTDOWN]) - msg->idiag_shutdown = nla_get_u8(tb[IDIAG_ATTR_SHUTDOWN]); + if (tb[INET_DIAG_SHUTDOWN]) + msg->idiag_shutdown = nla_get_u8(tb[INET_DIAG_SHUTDOWN]); - if (tb[IDIAG_ATTR_CONG]) - msg->idiag_cong = nla_strdup(tb[IDIAG_ATTR_CONG]); + if (tb[INET_DIAG_CONG]) + msg->idiag_cong = nla_strdup(tb[INET_DIAG_CONG]); - if (tb[IDIAG_ATTR_INFO]) - nla_memcpy(&msg->idiag_tcpinfo, tb[IDIAG_ATTR_INFO], + if (tb[INET_DIAG_INFO]) + nla_memcpy(&msg->idiag_tcpinfo, tb[INET_DIAG_INFO], sizeof(msg->idiag_tcpinfo)); - if (tb[IDIAG_ATTR_MEMINFO]) { + if (tb[INET_DIAG_MEMINFO]) { struct idiagnl_meminfo *minfo = idiagnl_meminfo_alloc(); struct inet_diag_meminfo *raw_minfo = NULL; @@ -668,7 +671,7 @@ int idiagnl_msg_parse(struct nlmsghdr *nlh, struct idiagnl_msg **result) goto errout_nomem; raw_minfo = (struct inet_diag_meminfo *) - nla_data(tb[IDIAG_ATTR_MEMINFO]); + nla_data(tb[INET_DIAG_MEMINFO]); idiagnl_meminfo_set_rmem(minfo, raw_minfo->idiag_rmem); idiagnl_meminfo_set_wmem(minfo, raw_minfo->idiag_wmem); @@ -678,7 +681,7 @@ int idiagnl_msg_parse(struct nlmsghdr *nlh, struct idiagnl_msg **result) msg->idiag_meminfo = minfo; } - if (tb[IDIAG_ATTR_VEGASINFO]) { + if (tb[INET_DIAG_VEGASINFO]) { struct idiagnl_vegasinfo *vinfo = idiagnl_vegasinfo_alloc(); struct tcpvegas_info *raw_vinfo = NULL; @@ -686,7 +689,7 @@ int idiagnl_msg_parse(struct nlmsghdr *nlh, struct idiagnl_msg **result) goto errout_nomem; raw_vinfo = (struct tcpvegas_info *) - nla_data(tb[IDIAG_ATTR_VEGASINFO]); + nla_data(tb[INET_DIAG_VEGASINFO]); idiagnl_vegasinfo_set_enabled(vinfo, raw_vinfo->tcpv_enabled); idiagnl_vegasinfo_set_rttcnt(vinfo, raw_vinfo->tcpv_rttcnt); @@ -696,8 +699,8 @@ int idiagnl_msg_parse(struct nlmsghdr *nlh, struct idiagnl_msg **result) msg->idiag_vegasinfo = vinfo; } - if (tb[IDIAG_ATTR_SKMEMINFO]) - nla_memcpy(&msg->idiag_skmeminfo, tb[IDIAG_ATTR_SKMEMINFO], + if (tb[INET_DIAG_SKMEMINFO]) + nla_memcpy(&msg->idiag_skmeminfo, tb[INET_DIAG_SKMEMINFO], sizeof(msg->idiag_skmeminfo)); *result = msg; @@ -750,8 +753,10 @@ struct nl_object_ops idiagnl_msg_obj_ops = { [NL_DUMP_STATS] = idiag_msg_dump_stats, }, .oo_keygen = idiagnl_keygen, + /* FIXME: using inet diag extended attributes as change flags (ce_mask) + * is very wrong. */ .oo_attrs2str = idiagnl_attrs2str, - .oo_id_attrs = (IDIAG_ATTR_INFO) + .oo_id_attrs = (INET_DIAG_INFO) }; /** @endcond */ From 3b5226e3a2c4dc53c0932b7a65196345ffe5245a Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 24 Nov 2014 17:14:49 +0100 Subject: [PATCH 05/13] idiag: deprecate netlink message type defines in idiagnl.h Acked-by: Thomas Graf Signed-off-by: Thomas Haller --- include/netlink/idiag/idiagnl.h | 3 +++ lib/idiag/idiag_msg_obj.c | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/include/netlink/idiag/idiagnl.h b/include/netlink/idiag/idiagnl.h index 58fe82e..9f3345a 100644 --- a/include/netlink/idiag/idiagnl.h +++ b/include/netlink/idiag/idiagnl.h @@ -21,6 +21,9 @@ extern "C" { /** * Inet Diag message types + * + * deprecated: use TCPDIAG_GETSOCK, DCCPDIAG_GETSOCK and + * INET_DIAG_GETSOCK_MAX from linux/inet_diag.h */ #define IDIAG_TCPDIAG_GETSOCK 18 #define IDIAG_DCCPDIAG_GETSOCK 19 diff --git a/lib/idiag/idiag_msg_obj.c b/lib/idiag/idiag_msg_obj.c index 321d83e..00c0562 100644 --- a/lib/idiag/idiag_msg_obj.c +++ b/lib/idiag/idiag_msg_obj.c @@ -71,8 +71,8 @@ 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" }, + { TCPDIAG_GETSOCK, NL_ACT_NEW, "new" }, + { DCCPDIAG_GETSOCK, NL_ACT_NEW, "new" }, END_OF_MSGTYPES_LIST, }, .co_protocol = NETLINK_INET_DIAG, From 94039ca48aad406acaffe6421ea2a06b05a69dde Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 24 Nov 2014 17:14:50 +0100 Subject: [PATCH 06/13] idiag: deprecate IDIAG_SS_* socket states These values mirror TCP_* socket states from 'netinit/tcp.h'. There is no good reason to expose a copy of those values. User space should use the original values (if they care). The only value that is actually useful is IDIAGNL_SS_ALL. Acked-by: Thomas Graf Signed-off-by: Thomas Haller --- include/netlink/idiag/idiagnl.h | 39 +++++++++++++++++++++------------ lib/idiag/idiag.c | 27 ++++++++++------------- src/idiag-socket-details.c | 2 +- 3 files changed, 38 insertions(+), 30 deletions(-) diff --git a/include/netlink/idiag/idiagnl.h b/include/netlink/idiag/idiagnl.h index 9f3345a..3b3b57e 100644 --- a/include/netlink/idiag/idiagnl.h +++ b/include/netlink/idiag/idiagnl.h @@ -32,28 +32,39 @@ extern "C" { /** * Socket state identifiers * @ingroup idiag + * @deprecated: use instead the TCP_* defines from netinet/tcp.h. */ 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 + IDIAG_SS_UNKNOWN = 0, + + IDIAG_SS_ESTABLISHED = 1, /* TCP_ESTABLISHED */ + IDIAG_SS_SYN_SENT = 2, /* TCP_SYN_SENT */ + IDIAG_SS_SYN_RECV = 3, /* TCP_SYN_RECV */ + IDIAG_SS_FIN_WAIT1 = 4, /* TCP_FIN_WAIT1 */ + IDIAG_SS_FIN_WAIT2 = 5, /* TCP_FIN_WAIT2 */ + IDIAG_SS_TIME_WAIT = 6, /* TCP_TIME_WAIT */ + IDIAG_SS_CLOSE = 7, /* TCP_CLOSE */ + IDIAG_SS_CLOSE_WAIT = 8, /* TCP_CLOSE_WAIT */ + IDIAG_SS_LAST_ACK = 9, /* TCP_LAST_ACK */ + IDIAG_SS_LISTEN = 10, /* TCP_LISTEN */ + IDIAG_SS_CLOSING = 11, /* TCP_CLOSING */ + + IDIAG_SS_MAX = 12, }; /** * Macro to represent all socket states. * @ingroup idiag */ -#define IDIAG_SS_ALL ((1< Date: Mon, 24 Nov 2014 17:14:51 +0100 Subject: [PATCH 07/13] idiag: deprecate IDIAG_TIMER_* value for IDIAGNL_TIMER_* Acked-by: Thomas Graf Signed-off-by: Thomas Haller --- include/netlink/idiag/idiagnl.h | 20 ++++++++++++++------ lib/idiag/idiag.c | 14 +++++++------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/include/netlink/idiag/idiagnl.h b/include/netlink/idiag/idiagnl.h index 3b3b57e..e6bc650 100644 --- a/include/netlink/idiag/idiagnl.h +++ b/include/netlink/idiag/idiagnl.h @@ -101,17 +101,25 @@ enum { #define IDIAG_SK_MEMINFO_BACKLOG SK_MEMINFO_BACKLOG #define IDIAG_SK_MEMINFO_VARS SK_MEMINFO_VARS +/* deprecated names. */ +#define IDIAG_TIMER_OFF IDIAGNL_TIMER_OFF +#define IDIAG_TIMER_ON IDIAGNL_TIMER_ON +#define IDIAG_TIMER_KEEPALIVE IDIAGNL_TIMER_KEEPALIVE +#define IDIAG_TIMER_TIMEWAIT IDIAGNL_TIMER_TIMEWAIT +#define IDIAG_TIMER_PERSIST IDIAGNL_TIMER_PERSIST +#define IDIAG_TIMER_UNKNOWN IDIAGNL_TIMER_UNKNOWN + /** * Socket timer indentifiers * @ingroupd idiag */ enum { - IDIAG_TIMER_OFF, - IDIAG_TIMER_ON, - IDIAG_TIMER_KEEPALIVE, - IDIAG_TIMER_TIMEWAIT, - IDIAG_TIMER_PERSIST, - IDIAG_TIMER_UNKNOWN, + IDIAGNL_TIMER_OFF = 0, + IDIAGNL_TIMER_ON = 1, + IDIAGNL_TIMER_KEEPALIVE = 2, + IDIAGNL_TIMER_TIMEWAIT = 3, + IDIAGNL_TIMER_PERSIST = 4, + IDIAGNL_TIMER_UNKNOWN = 5, }; extern char * idiagnl_state2str(int, char *, size_t); diff --git a/lib/idiag/idiag.c b/lib/idiag/idiag.c index 303ffea..d8f5065 100644 --- a/lib/idiag/idiag.c +++ b/lib/idiag/idiag.c @@ -123,17 +123,17 @@ int idiagnl_str2state(const char *name) } 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), + __ADD(IDIAGNL_TIMER_OFF, off), + __ADD(IDIAGNL_TIMER_ON, on), + __ADD(IDIAGNL_TIMER_KEEPALIVE, keepalive), + __ADD(IDIAGNL_TIMER_TIMEWAIT, timewait), + __ADD(IDIAGNL_TIMER_PERSIST, persist), + __ADD(IDIAGNL_TIMER_UNKNOWN, unknown), }; /** * Convert inet diag timer types to strings. - * @arg timer inetdiag timer (e.g., IDIAG_TIMER_ON) + * @arg timer inetdiag timer (e.g., IDIAGNL_TIMER_ON) * @arg buf output buffer which will hold string result * @arg len length in bytes of the output buffer * From 0e13bb44b83fd04673091ae6b75e5de598ea84c3 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 24 Nov 2014 17:14:52 +0100 Subject: [PATCH 08/13] idiag: reorder idiagnl.h to have deprecated functions at the top Acked-by: Thomas Graf Signed-off-by: Thomas Haller --- include/netlink/idiag/idiagnl.h | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/include/netlink/idiag/idiagnl.h b/include/netlink/idiag/idiagnl.h index e6bc650..c99f83b 100644 --- a/include/netlink/idiag/idiagnl.h +++ b/include/netlink/idiag/idiagnl.h @@ -19,6 +19,11 @@ extern "C" { #endif +/************************************************************* + * The following part contains DEPRECATED names and defines. + * Don't use them. + *************************************************************/ + /** * Inet Diag message types * @@ -52,12 +57,6 @@ enum { IDIAG_SS_MAX = 12, }; -/** - * Macro to represent all socket states. - * @ingroup idiag - */ -#define IDIAGNL_SS_ALL (((1<<12)-1)) - /** * Macro to represent all socket states. * @ingroup idiag @@ -90,7 +89,7 @@ enum { }; -/* Keep these only for compatibility, DO NOT USE THEM */ +/* deprectated keep these only for compatibility, DO NOT USE THEM */ #define IDIAG_SK_MEMINFO_RMEM_ALLOC SK_MEMINFO_RMEM_ALLOC #define IDIAG_SK_MEMINFO_RCVBUF SK_MEMINFO_RCVBUF #define IDIAG_SK_MEMINFO_WMEM_ALLOC SK_MEMINFO_WMEM_ALLOC @@ -109,6 +108,14 @@ enum { #define IDIAG_TIMER_PERSIST IDIAGNL_TIMER_PERSIST #define IDIAG_TIMER_UNKNOWN IDIAGNL_TIMER_UNKNOWN +/*************************************************************/ + +/** + * Macro to represent all socket states. + * @ingroup idiag + */ +#define IDIAGNL_SS_ALL (((1<<12)-1)) + /** * Socket timer indentifiers * @ingroupd idiag From f40fd71701e444d91a02c7f06ffbd4fcf232c9b9 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 24 Nov 2014 17:14:53 +0100 Subject: [PATCH 09/13] idiag: fix memory leak in idiagnl_msg_set_cong() Acked-by: Thomas Graf Signed-off-by: Thomas Haller --- lib/idiag/idiag_msg_obj.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/idiag/idiag_msg_obj.c b/lib/idiag/idiag_msg_obj.c index 00c0562..1d9fde8 100644 --- a/lib/idiag/idiag_msg_obj.c +++ b/lib/idiag/idiag_msg_obj.c @@ -324,6 +324,7 @@ char *idiagnl_msg_get_cong(const struct idiagnl_msg *msg) void idiagnl_msg_set_cong(struct idiagnl_msg *msg, char *cong) { + free (msg->idiag_cong); msg->idiag_cong = strdup(cong); } From 39ca54ab4d9464e8951a0c67fe33ff1ce906e642 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 24 Nov 2014 17:14:54 +0100 Subject: [PATCH 10/13] idiag: fix idiagnl_msg_clone() For one, we did not clone all pointer values. Hence, every cloned object was very broken and resulted in dangling pointers and double free/unref. Apparently nobody was really using this function up to now. Also, fix the return cases for NLE_NOMEM, so that we did not assume ownership of pointers in 'src'. Acked-by: Thomas Graf Signed-off-by: Thomas Haller --- lib/idiag/idiag_msg_obj.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/lib/idiag/idiag_msg_obj.c b/lib/idiag/idiag_msg_obj.c index 1d9fde8..b212f69 100644 --- a/lib/idiag/idiag_msg_obj.c +++ b/lib/idiag/idiag_msg_obj.c @@ -572,13 +572,36 @@ 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) + dst->idiag_cong = NULL; + dst->idiag_src = NULL; + dst->idiag_dst = NULL; + dst->idiag_meminfo = NULL; + dst->idiag_vegasinfo = NULL; + + if (src->idiag_cong) { + if (!(dst->idiag_cong = strdup(src->idiag_cong))) + return -NLE_NOMEM; + } + + if (src->idiag_src) { if (!(dst->idiag_src = nl_addr_clone(src->idiag_src))) return -NLE_NOMEM; + } - if (src->idiag_dst) + if (src->idiag_dst) { if (!(dst->idiag_dst = nl_addr_clone(src->idiag_dst))) return -NLE_NOMEM; + } + + if (src->idiag_meminfo) { + if (!(dst->idiag_meminfo = (struct idiagnl_meminfo *) nl_object_clone((struct nl_object *) src->idiag_meminfo))) + return -NLE_NOMEM; + } + + if (src->idiag_vegasinfo) { + if (!(dst->idiag_vegasinfo = (struct idiagnl_vegasinfo *) nl_object_clone((struct nl_object *) src->idiag_vegasinfo))) + return -NLE_NOMEM; + } return 0; } From 2ee5cf55f327d41d770ec3a973182be6171f3e51 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 24 Nov 2014 17:14:55 +0100 Subject: [PATCH 11/13] idiag: remove clone functions from trivial structures A oo_clone() function is only needed for complex sturctures to deep copy an object. Acked-by: Thomas Graf Signed-off-by: Thomas Haller --- lib/idiag/idiag_meminfo_obj.c | 11 ----------- lib/idiag/idiag_vegasinfo_obj.c | 12 ------------ 2 files changed, 23 deletions(-) diff --git a/lib/idiag/idiag_meminfo_obj.c b/lib/idiag/idiag_meminfo_obj.c index a60f497..7a044f4 100644 --- a/lib/idiag/idiag_meminfo_obj.c +++ b/lib/idiag/idiag_meminfo_obj.c @@ -80,21 +80,10 @@ void idiagnl_meminfo_set_tmem(struct idiagnl_meminfo *minfo, uint32_t 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_vegasinfo_obj.c b/lib/idiag/idiag_vegasinfo_obj.c index 5279e83..ffeb357 100644 --- a/lib/idiag/idiag_vegasinfo_obj.c +++ b/lib/idiag/idiag_vegasinfo_obj.c @@ -83,22 +83,10 @@ void idiagnl_vegasinfo_set_minrtt(struct idiagnl_vegasinfo *vinfo, uint32_t } /** @} */ -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 */ /** @} */ From 8eea9e927f4cb1ec2f89d2e7cb22008855cda8db Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 24 Nov 2014 17:14:56 +0100 Subject: [PATCH 12/13] idiag: add change attributes for idiag_msg_obj Acked-by: Thomas Graf Signed-off-by: Thomas Haller --- lib/idiag/idiag_msg_obj.c | 141 ++++++++++++++++++++++++++++++++++---- 1 file changed, 127 insertions(+), 14 deletions(-) diff --git a/lib/idiag/idiag_msg_obj.c b/lib/idiag/idiag_msg_obj.c index b212f69..034faa9 100644 --- a/lib/idiag/idiag_msg_obj.c +++ b/lib/idiag/idiag_msg_obj.c @@ -17,7 +17,32 @@ #include +/** @cond SKIP */ +#define IDIAGNL_ATTR_FAMILY (0x1 << 1) +#define IDIAGNL_ATTR_STATE (0x1 << 2) +#define IDIAGNL_ATTR_TIMER (0x1 << 3) +#define IDIAGNL_ATTR_RETRANS (0x1 << 4) +#define IDIAGNL_ATTR_SPORT (0x1 << 5) +#define IDIAGNL_ATTR_DPORT (0x1 << 6) +#define IDIAGNL_ATTR_SRC (0x1 << 7) +#define IDIAGNL_ATTR_DST (0x1 << 8) +#define IDIAGNL_ATTR_IFINDEX (0x1 << 9) +#define IDIAGNL_ATTR_EXPIRES (0x1 << 10) +#define IDIAGNL_ATTR_RQUEUE (0x1 << 11) +#define IDIAGNL_ATTR_WQUEUE (0x1 << 12) +#define IDIAGNL_ATTR_UID (0x1 << 13) +#define IDIAGNL_ATTR_INODE (0x1 << 14) +#define IDIAGNL_ATTR_TOS (0x1 << 15) +#define IDIAGNL_ATTR_TCLASS (0x1 << 16) +#define IDIAGNL_ATTR_SHUTDOWN (0x1 << 17) +#define IDIAGNL_ATTR_CONG (0x1 << 18) +#define IDIAGNL_ATTR_MEMINFO (0x1 << 19) +#define IDIAGNL_ATTR_VEGASINFO (0x1 << 20) +#define IDIAGNL_ATTR_TCPINFO (0x1 << 21) +#define IDIAGNL_ATTR_SKMEMINFO (0x1 << 22) + #define _INET_DIAG_ALL ((1<<(INET_DIAG_MAX+1))-1) +/** @endcond */ /** * @ingroup idiag @@ -143,6 +168,7 @@ uint8_t idiagnl_msg_get_family(const struct idiagnl_msg *msg) void idiagnl_msg_set_family(struct idiagnl_msg *msg, uint8_t family) { msg->idiag_family = family; + msg->ce_mask |= IDIAGNL_ATTR_FAMILY; } uint8_t idiagnl_msg_get_state(const struct idiagnl_msg *msg) @@ -153,6 +179,7 @@ uint8_t idiagnl_msg_get_state(const struct idiagnl_msg *msg) void idiagnl_msg_set_state(struct idiagnl_msg *msg, uint8_t state) { msg->idiag_state = state; + msg->ce_mask |= IDIAGNL_ATTR_STATE; } uint8_t idiagnl_msg_get_timer(const struct idiagnl_msg *msg) @@ -163,6 +190,7 @@ uint8_t idiagnl_msg_get_timer(const struct idiagnl_msg *msg) void idiagnl_msg_set_timer(struct idiagnl_msg *msg, uint8_t timer) { msg->idiag_timer = timer; + msg->ce_mask |= IDIAGNL_ATTR_TIMER; } uint8_t idiagnl_msg_get_retrans(const struct idiagnl_msg *msg) @@ -173,6 +201,7 @@ uint8_t idiagnl_msg_get_retrans(const struct idiagnl_msg *msg) void idiagnl_msg_set_retrans(struct idiagnl_msg *msg, uint8_t retrans) { msg->idiag_retrans = retrans; + msg->ce_mask |= IDIAGNL_ATTR_RETRANS; } uint16_t idiagnl_msg_get_sport(struct idiagnl_msg *msg) @@ -183,6 +212,7 @@ uint16_t idiagnl_msg_get_sport(struct idiagnl_msg *msg) void idiagnl_msg_set_sport(struct idiagnl_msg *msg, uint16_t port) { msg->idiag_sport = port; + msg->ce_mask |= IDIAGNL_ATTR_SPORT; } uint16_t idiagnl_msg_get_dport(struct idiagnl_msg *msg) @@ -193,6 +223,7 @@ uint16_t idiagnl_msg_get_dport(struct idiagnl_msg *msg) void idiagnl_msg_set_dport(struct idiagnl_msg *msg, uint16_t port) { msg->idiag_dport = port; + msg->ce_mask |= IDIAGNL_ATTR_DPORT; } struct nl_addr *idiagnl_msg_get_src(const struct idiagnl_msg *msg) @@ -207,6 +238,7 @@ int idiagnl_msg_set_src(struct idiagnl_msg *msg, struct nl_addr *addr) nl_addr_get(addr); msg->idiag_src = addr; + msg->ce_mask |= IDIAGNL_ATTR_SRC; return 0; } @@ -223,6 +255,7 @@ int idiagnl_msg_set_dst(struct idiagnl_msg *msg, struct nl_addr *addr) nl_addr_get(addr); msg->idiag_dst = addr; + msg->ce_mask |= IDIAGNL_ATTR_DST; return 0; } @@ -235,6 +268,7 @@ uint32_t idiagnl_msg_get_ifindex(const struct idiagnl_msg *msg) void idiagnl_msg_set_ifindex(struct idiagnl_msg *msg, uint32_t ifindex) { msg->idiag_ifindex = ifindex; + msg->ce_mask |= IDIAGNL_ATTR_IFINDEX; } uint32_t idiagnl_msg_get_expires(const struct idiagnl_msg *msg) @@ -245,6 +279,7 @@ uint32_t idiagnl_msg_get_expires(const struct idiagnl_msg *msg) void idiagnl_msg_set_expires(struct idiagnl_msg *msg, uint32_t expires) { msg->idiag_expires = expires; + msg->ce_mask |= IDIAGNL_ATTR_EXPIRES; } uint32_t idiagnl_msg_get_rqueue(const struct idiagnl_msg *msg) @@ -255,6 +290,7 @@ uint32_t idiagnl_msg_get_rqueue(const struct idiagnl_msg *msg) void idiagnl_msg_set_rqueue(struct idiagnl_msg *msg, uint32_t rqueue) { msg->idiag_rqueue = rqueue; + msg->ce_mask |= IDIAGNL_ATTR_RQUEUE; } uint32_t idiagnl_msg_get_wqueue(const struct idiagnl_msg *msg) @@ -265,6 +301,7 @@ uint32_t idiagnl_msg_get_wqueue(const struct idiagnl_msg *msg) void idiagnl_msg_set_wqueue(struct idiagnl_msg *msg, uint32_t wqueue) { msg->idiag_wqueue = wqueue; + msg->ce_mask |= IDIAGNL_ATTR_WQUEUE; } uint32_t idiagnl_msg_get_uid(const struct idiagnl_msg *msg) @@ -275,6 +312,7 @@ uint32_t idiagnl_msg_get_uid(const struct idiagnl_msg *msg) void idiagnl_msg_set_uid(struct idiagnl_msg *msg, uint32_t uid) { msg->idiag_uid = uid; + msg->ce_mask |= IDIAGNL_ATTR_UID; } uint32_t idiagnl_msg_get_inode(const struct idiagnl_msg *msg) @@ -285,6 +323,7 @@ uint32_t idiagnl_msg_get_inode(const struct idiagnl_msg *msg) void idiagnl_msg_set_inode(struct idiagnl_msg *msg, uint32_t inode) { msg->idiag_inode = inode; + msg->ce_mask |= IDIAGNL_ATTR_INODE; } uint8_t idiagnl_msg_get_tos(const struct idiagnl_msg *msg) @@ -295,6 +334,7 @@ uint8_t idiagnl_msg_get_tos(const struct idiagnl_msg *msg) void idiagnl_msg_set_tos(struct idiagnl_msg *msg, uint8_t tos) { msg->idiag_tos = tos; + msg->ce_mask |= IDIAGNL_ATTR_TOS; } uint8_t idiagnl_msg_get_tclass(const struct idiagnl_msg *msg) @@ -305,6 +345,7 @@ uint8_t idiagnl_msg_get_tclass(const struct idiagnl_msg *msg) void idiagnl_msg_set_tclass(struct idiagnl_msg *msg, uint8_t tclass) { msg->idiag_tclass = tclass; + msg->ce_mask |= IDIAGNL_ATTR_TCLASS; } uint8_t idiagnl_msg_get_shutdown(const struct idiagnl_msg *msg) @@ -315,6 +356,7 @@ uint8_t idiagnl_msg_get_shutdown(const struct idiagnl_msg *msg) void idiagnl_msg_set_shutdown(struct idiagnl_msg *msg, uint8_t shutdown) { msg->idiag_shutdown = shutdown; + msg->ce_mask |= IDIAGNL_ATTR_SHUTDOWN; } char *idiagnl_msg_get_cong(const struct idiagnl_msg *msg) @@ -326,6 +368,7 @@ void idiagnl_msg_set_cong(struct idiagnl_msg *msg, char *cong) { free (msg->idiag_cong); msg->idiag_cong = strdup(cong); + msg->ce_mask |= IDIAGNL_ATTR_CONG; } struct idiagnl_meminfo *idiagnl_msg_get_meminfo(const struct idiagnl_msg *msg) @@ -333,14 +376,14 @@ 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) +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; + msg->ce_mask |= IDIAGNL_ATTR_MEMINFO; } struct idiagnl_vegasinfo *idiagnl_msg_get_vegasinfo(const struct idiagnl_msg *msg) @@ -348,14 +391,14 @@ struct idiagnl_vegasinfo *idiagnl_msg_get_vegasinfo(const struct idiagnl_msg *ms return msg->idiag_vegasinfo; } -void idiagnl_msg_set_vegasinfo(struct idiagnl_msg *msg, struct idiagnl_vegasinfo - *vinfo) +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; + msg->ce_mask |= IDIAGNL_ATTR_VEGASINFO; } struct tcp_info idiagnl_msg_get_tcpinfo(const struct idiagnl_msg *msg) @@ -366,6 +409,7 @@ struct tcp_info idiagnl_msg_get_tcpinfo(const struct idiagnl_msg *msg) void idiagnl_msg_set_tcpinfo(struct idiagnl_msg *msg, struct tcp_info *tinfo) { memcpy(&msg->idiag_tcpinfo, tinfo, sizeof(struct tcp_info)); + msg->ce_mask |= IDIAGNL_ATTR_TCPINFO; } /** @} */ @@ -577,30 +621,40 @@ static int idiagnl_msg_clone(struct nl_object *_dst, struct nl_object *_src) dst->idiag_dst = NULL; dst->idiag_meminfo = NULL; dst->idiag_vegasinfo = NULL; + dst->ce_mask &= ~(IDIAGNL_ATTR_CONG | + IDIAGNL_ATTR_SRC | + IDIAGNL_ATTR_DST | + IDIAGNL_ATTR_MEMINFO | + IDIAGNL_ATTR_VEGASINFO); if (src->idiag_cong) { if (!(dst->idiag_cong = strdup(src->idiag_cong))) return -NLE_NOMEM; + dst->ce_mask |= IDIAGNL_ATTR_CONG; } if (src->idiag_src) { if (!(dst->idiag_src = nl_addr_clone(src->idiag_src))) return -NLE_NOMEM; + dst->ce_mask |= IDIAGNL_ATTR_SRC; } if (src->idiag_dst) { if (!(dst->idiag_dst = nl_addr_clone(src->idiag_dst))) return -NLE_NOMEM; + dst->ce_mask |= IDIAGNL_ATTR_DST; } if (src->idiag_meminfo) { if (!(dst->idiag_meminfo = (struct idiagnl_meminfo *) nl_object_clone((struct nl_object *) src->idiag_meminfo))) return -NLE_NOMEM; + dst->ce_mask |= IDIAGNL_ATTR_MEMINFO; } if (src->idiag_vegasinfo) { if (!(dst->idiag_vegasinfo = (struct idiagnl_vegasinfo *) nl_object_clone((struct nl_object *) src->idiag_vegasinfo))) return -NLE_NOMEM; + dst->ce_mask |= IDIAGNL_ATTR_VEGASINFO; } return 0; @@ -649,6 +703,19 @@ int idiagnl_msg_parse(struct nlmsghdr *nlh, struct idiagnl_msg **result) msg->idiag_dport = raw_msg->id.idiag_dport; msg->idiag_ifindex = raw_msg->id.idiag_if; + msg->ce_mask = (IDIAGNL_ATTR_FAMILY | + IDIAGNL_ATTR_STATE | + IDIAGNL_ATTR_TIMER | + IDIAGNL_ATTR_RETRANS | + IDIAGNL_ATTR_EXPIRES | + IDIAGNL_ATTR_RQUEUE | + IDIAGNL_ATTR_WQUEUE | + IDIAGNL_ATTR_UID | + IDIAGNL_ATTR_INODE | + IDIAGNL_ATTR_SPORT | + IDIAGNL_ATTR_DPORT | + IDIAGNL_ATTR_IFINDEX); + dst = nl_addr_build(raw_msg->idiag_family, raw_msg->id.idiag_dst, sizeof(raw_msg->id.idiag_dst)); if (!dst) @@ -671,21 +738,31 @@ int idiagnl_msg_parse(struct nlmsghdr *nlh, struct idiagnl_msg **result) nl_addr_put(src); - if (tb[INET_DIAG_TOS]) + if (tb[INET_DIAG_TOS]) { msg->idiag_tos = nla_get_u8(tb[INET_DIAG_TOS]); + msg->ce_mask |= IDIAGNL_ATTR_TOS; + } - if (tb[INET_DIAG_TCLASS]) + if (tb[INET_DIAG_TCLASS]) { msg->idiag_tclass = nla_get_u8(tb[INET_DIAG_TCLASS]); + msg->ce_mask |= IDIAGNL_ATTR_TCLASS; + } - if (tb[INET_DIAG_SHUTDOWN]) + if (tb[INET_DIAG_SHUTDOWN]) { msg->idiag_shutdown = nla_get_u8(tb[INET_DIAG_SHUTDOWN]); + msg->ce_mask |= IDIAGNL_ATTR_SHUTDOWN; + } - if (tb[INET_DIAG_CONG]) + if (tb[INET_DIAG_CONG]) { msg->idiag_cong = nla_strdup(tb[INET_DIAG_CONG]); + msg->ce_mask |= IDIAGNL_ATTR_CONG; + } - if (tb[INET_DIAG_INFO]) + if (tb[INET_DIAG_INFO]) { nla_memcpy(&msg->idiag_tcpinfo, tb[INET_DIAG_INFO], sizeof(msg->idiag_tcpinfo)); + msg->ce_mask |= IDIAGNL_ATTR_TCPINFO; + } if (tb[INET_DIAG_MEMINFO]) { struct idiagnl_meminfo *minfo = idiagnl_meminfo_alloc(); @@ -703,6 +780,7 @@ int idiagnl_msg_parse(struct nlmsghdr *nlh, struct idiagnl_msg **result) idiagnl_meminfo_set_tmem(minfo, raw_minfo->idiag_tmem); msg->idiag_meminfo = minfo; + msg->ce_mask |= IDIAGNL_ATTR_MEMINFO; } if (tb[INET_DIAG_VEGASINFO]) { @@ -721,11 +799,14 @@ int idiagnl_msg_parse(struct nlmsghdr *nlh, struct idiagnl_msg **result) idiagnl_vegasinfo_set_minrtt(vinfo, raw_vinfo->tcpv_minrtt); msg->idiag_vegasinfo = vinfo; + msg->ce_mask |= IDIAGNL_ATTR_VEGASINFO; } - if (tb[INET_DIAG_SKMEMINFO]) + if (tb[INET_DIAG_SKMEMINFO]) { nla_memcpy(&msg->idiag_skmeminfo, tb[INET_DIAG_SKMEMINFO], sizeof(msg->idiag_skmeminfo)); + msg->ce_mask |= IDIAGNL_ATTR_SKMEMINFO; + } *result = msg; return 0; @@ -739,6 +820,37 @@ errout_nomem: goto errout; } +static const struct trans_tbl idiagnl_attrs[] = { + __ADD(IDIAGNL_ATTR_FAMILY, family), + __ADD(IDIAGNL_ATTR_STATE, state), + __ADD(IDIAGNL_ATTR_TIMER, timer), + __ADD(IDIAGNL_ATTR_RETRANS, retrans), + __ADD(IDIAGNL_ATTR_SPORT, sport), + __ADD(IDIAGNL_ATTR_DPORT, dport), + __ADD(IDIAGNL_ATTR_SRC, src), + __ADD(IDIAGNL_ATTR_DST, dst), + __ADD(IDIAGNL_ATTR_IFINDEX, ifindex), + __ADD(IDIAGNL_ATTR_EXPIRES, expires), + __ADD(IDIAGNL_ATTR_RQUEUE, rqueue), + __ADD(IDIAGNL_ATTR_WQUEUE, wqueue), + __ADD(IDIAGNL_ATTR_UID, uid), + __ADD(IDIAGNL_ATTR_INODE, inode), + __ADD(IDIAGNL_ATTR_TOS, tos), + __ADD(IDIAGNL_ATTR_TCLASS, tclass), + __ADD(IDIAGNL_ATTR_SHUTDOWN, shutdown), + __ADD(IDIAGNL_ATTR_CONG, cong), + __ADD(IDIAGNL_ATTR_MEMINFO, meminfo), + __ADD(IDIAGNL_ATTR_VEGASINFO, vegasinfo), + __ADD(IDIAGNL_ATTR_TCPINFO, tcpinfo), + __ADD(IDIAGNL_ATTR_SKMEMINFO, skmeminfo), +}; + +static char *_idiagnl_attrs2str(int attrs, char *buf, size_t len) +{ + return __flags2str(attrs, buf, len, idiagnl_attrs, + ARRAY_SIZE(idiagnl_attrs)); +} + static void idiagnl_keygen(struct nl_object *obj, uint32_t *hashkey, uint32_t table_sz) { @@ -777,10 +889,11 @@ struct nl_object_ops idiagnl_msg_obj_ops = { [NL_DUMP_STATS] = idiag_msg_dump_stats, }, .oo_keygen = idiagnl_keygen, - /* FIXME: using inet diag extended attributes as change flags (ce_mask) - * is very wrong. */ - .oo_attrs2str = idiagnl_attrs2str, - .oo_id_attrs = (INET_DIAG_INFO) + .oo_attrs2str = _idiagnl_attrs2str, + .oo_id_attrs = (IDIAGNL_ATTR_FAMILY | + IDIAGNL_ATTR_STATE | + IDIAGNL_ATTR_SPORT | + IDIAGNL_ATTR_DPORT), }; /** @endcond */ From fac840d1f375fb7741d0ee75b871020edc11209b Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 24 Nov 2014 17:14:57 +0100 Subject: [PATCH 13/13] idiag: add a oo_compare() function for idiag_msg objects Having a oo_keygen() function only makes sense together with a oo_compare() function because after hashing, you still have to compare the objects for equality (in case of hash collission). Fixes: 9c066b9271493ce3efff0b9d7b6e424990bba3f2 Acked-by: Thomas Graf Signed-off-by: Thomas Haller --- lib/idiag/idiag_msg_obj.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lib/idiag/idiag_msg_obj.c b/lib/idiag/idiag_msg_obj.c index 034faa9..8199536 100644 --- a/lib/idiag/idiag_msg_obj.c +++ b/lib/idiag/idiag_msg_obj.c @@ -851,6 +851,22 @@ static char *_idiagnl_attrs2str(int attrs, char *buf, size_t len) ARRAY_SIZE(idiagnl_attrs)); } +static int idiagnl_compare(struct nl_object *_a, struct nl_object *_b, + uint32_t attrs, int flags) +{ + struct idiagnl_msg *a = (struct idiagnl_msg *) _a; + struct idiagnl_msg *b = (struct idiagnl_msg *) _b; + int diff = 0; + +#define _DIFF(ATTR, EXPR) ATTR_DIFF(attrs, IDIAGNL_ATTR_##ATTR, a, b, EXPR) + diff |= _DIFF(FAMILY, a->idiag_family != b->idiag_family); + diff |= _DIFF(STATE, a->idiag_state != b->idiag_state); + diff |= _DIFF(SPORT, a->idiag_sport != b->idiag_sport); + diff |= _DIFF(DPORT, a->idiag_dport != b->idiag_dport); +#undef _DIFF + return diff; +} + static void idiagnl_keygen(struct nl_object *obj, uint32_t *hashkey, uint32_t table_sz) { @@ -888,6 +904,7 @@ struct nl_object_ops idiagnl_msg_obj_ops = { [NL_DUMP_DETAILS] = idiag_msg_dump_details, [NL_DUMP_STATS] = idiag_msg_dump_stats, }, + .oo_compare = idiagnl_compare, .oo_keygen = idiagnl_keygen, .oo_attrs2str = _idiagnl_attrs2str, .oo_id_attrs = (IDIAGNL_ATTR_FAMILY |