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_ */ diff --git a/include/netlink/idiag/idiagnl.h b/include/netlink/idiag/idiagnl.h index 64bccd7..c99f83b 100644 --- a/include/netlink/idiag/idiagnl.h +++ b/include/netlink/idiag/idiagnl.h @@ -19,8 +19,16 @@ extern "C" { #endif +/************************************************************* + * The following part contains DEPRECATED names and defines. + * Don't use them. + *************************************************************/ + /** * 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 @@ -29,53 +37,59 @@ 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 + * @deprecated */ -#define IDIAG_SS_ALL ((1< #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 * @defgroup idiagnl_msg Inet Diag Messages @@ -61,15 +89,15 @@ 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 = { .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, @@ -140,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) @@ -150,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) @@ -160,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) @@ -170,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) @@ -180,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) @@ -190,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) @@ -204,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; } @@ -220,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; } @@ -232,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) @@ -242,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) @@ -252,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) @@ -262,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) @@ -272,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) @@ -282,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) @@ -292,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) @@ -302,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) @@ -312,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) @@ -321,7 +366,9 @@ 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); + msg->ce_mask |= IDIAGNL_ATTR_CONG; } struct idiagnl_meminfo *idiagnl_msg_get_meminfo(const struct idiagnl_msg *msg) @@ -329,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) @@ -344,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) @@ -362,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; } /** @} */ @@ -568,27 +616,60 @@ 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; + 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 (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; } -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 +677,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, + err = nlmsg_parse(nlh, sizeof(struct inet_diag_msg), tb, INET_DIAG_MAX, ext_policy); if (err < 0) goto errout; @@ -622,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) @@ -644,23 +738,33 @@ 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]); + msg->ce_mask |= IDIAGNL_ATTR_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]); + msg->ce_mask |= IDIAGNL_ATTR_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]); + msg->ce_mask |= IDIAGNL_ATTR_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]); + msg->ce_mask |= IDIAGNL_ATTR_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)); + msg->ce_mask |= IDIAGNL_ATTR_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 +772,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); @@ -676,9 +780,10 @@ 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[IDIAG_ATTR_VEGASINFO]) { + if (tb[INET_DIAG_VEGASINFO]) { struct idiagnl_vegasinfo *vinfo = idiagnl_vegasinfo_alloc(); struct tcpvegas_info *raw_vinfo = NULL; @@ -686,7 +791,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); @@ -694,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[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)); + msg->ce_mask |= IDIAGNL_ATTR_SKMEMINFO; + } *result = msg; return 0; @@ -712,6 +820,53 @@ 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 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) { @@ -749,9 +904,13 @@ 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 = (IDIAG_ATTR_INFO) + .oo_attrs2str = _idiagnl_attrs2str, + .oo_id_attrs = (IDIAGNL_ATTR_FAMILY | + IDIAGNL_ATTR_STATE | + IDIAGNL_ATTR_SPORT | + IDIAGNL_ATTR_DPORT), }; /** @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 */ /** @} */ diff --git a/src/idiag-socket-details.c b/src/idiag-socket-details.c index 9568676..17bcef2 100644 --- a/src/idiag-socket-details.c +++ b/src/idiag-socket-details.c @@ -72,7 +72,7 @@ int main(int argc, char *argv[]) } } - if ((err = idiagnl_msg_alloc_cache(sock, AF_INET, IDIAG_SS_ALL, + if ((err = idiagnl_msg_alloc_cache(sock, AF_INET, IDIAGNL_SS_ALL, &idiag_cache))) { nl_cli_fatal(err, "Unable to allocate idiag msg cache: %s", nl_geterror(err));