mirror of https://gitee.com/openkylin/linux.git
[INET_DIAG]: Introduce inet_twsk_diag_dump & inet_twsk_diag_fill
To properly dump TIME_WAIT sockets and to reduce complexity a bit by having per socket class accessor routines. Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
4e852c0279
commit
c7d58aabdc
|
@ -70,20 +70,22 @@ static int inet_diag_fill(struct sk_buff *skb, struct sock *sk,
|
|||
nlh->nlmsg_flags = nlmsg_flags;
|
||||
|
||||
r = NLMSG_DATA(nlh);
|
||||
if (sk->sk_state != TCP_TIME_WAIT) {
|
||||
if (ext & (1 << (INET_DIAG_MEMINFO - 1)))
|
||||
minfo = INET_DIAG_PUT(skb, INET_DIAG_MEMINFO,
|
||||
sizeof(*minfo));
|
||||
if (ext & (1 << (INET_DIAG_INFO - 1)))
|
||||
info = INET_DIAG_PUT(skb, INET_DIAG_INFO,
|
||||
handler->idiag_info_size);
|
||||
BUG_ON(sk->sk_state == TCP_TIME_WAIT);
|
||||
|
||||
if ((ext & (1 << (INET_DIAG_CONG - 1))) && icsk->icsk_ca_ops) {
|
||||
size_t len = strlen(icsk->icsk_ca_ops->name);
|
||||
strcpy(INET_DIAG_PUT(skb, INET_DIAG_CONG, len + 1),
|
||||
icsk->icsk_ca_ops->name);
|
||||
}
|
||||
if (ext & (1 << (INET_DIAG_MEMINFO - 1)))
|
||||
minfo = INET_DIAG_PUT(skb, INET_DIAG_MEMINFO, sizeof(*minfo));
|
||||
|
||||
if (ext & (1 << (INET_DIAG_INFO - 1)))
|
||||
info = INET_DIAG_PUT(skb, INET_DIAG_INFO,
|
||||
handler->idiag_info_size);
|
||||
|
||||
if ((ext & (1 << (INET_DIAG_CONG - 1))) && icsk->icsk_ca_ops) {
|
||||
const size_t len = strlen(icsk->icsk_ca_ops->name);
|
||||
|
||||
strcpy(INET_DIAG_PUT(skb, INET_DIAG_CONG, len + 1),
|
||||
icsk->icsk_ca_ops->name);
|
||||
}
|
||||
|
||||
r->idiag_family = sk->sk_family;
|
||||
r->idiag_state = sk->sk_state;
|
||||
r->idiag_timer = 0;
|
||||
|
@ -93,37 +95,6 @@ static int inet_diag_fill(struct sk_buff *skb, struct sock *sk,
|
|||
r->id.idiag_cookie[0] = (u32)(unsigned long)sk;
|
||||
r->id.idiag_cookie[1] = (u32)(((unsigned long)sk >> 31) >> 1);
|
||||
|
||||
if (r->idiag_state == TCP_TIME_WAIT) {
|
||||
const struct inet_timewait_sock *tw = inet_twsk(sk);
|
||||
long tmo = tw->tw_ttd - jiffies;
|
||||
if (tmo < 0)
|
||||
tmo = 0;
|
||||
|
||||
r->id.idiag_sport = tw->tw_sport;
|
||||
r->id.idiag_dport = tw->tw_dport;
|
||||
r->id.idiag_src[0] = tw->tw_rcv_saddr;
|
||||
r->id.idiag_dst[0] = tw->tw_daddr;
|
||||
r->idiag_state = tw->tw_substate;
|
||||
r->idiag_timer = 3;
|
||||
r->idiag_expires = (tmo * 1000 + HZ - 1) / HZ;
|
||||
r->idiag_rqueue = 0;
|
||||
r->idiag_wqueue = 0;
|
||||
r->idiag_uid = 0;
|
||||
r->idiag_inode = 0;
|
||||
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
|
||||
if (r->idiag_family == AF_INET6) {
|
||||
const struct inet6_timewait_sock *tw6 = inet6_twsk(sk);
|
||||
|
||||
ipv6_addr_copy((struct in6_addr *)r->id.idiag_src,
|
||||
&tw6->tw_v6_rcv_saddr);
|
||||
ipv6_addr_copy((struct in6_addr *)r->id.idiag_dst,
|
||||
&tw6->tw_v6_daddr);
|
||||
}
|
||||
#endif
|
||||
nlh->nlmsg_len = skb->tail - b;
|
||||
return skb->len;
|
||||
}
|
||||
|
||||
r->id.idiag_sport = inet->sport;
|
||||
r->id.idiag_dport = inet->dport;
|
||||
r->id.idiag_src[0] = inet->rcv_saddr;
|
||||
|
@ -185,6 +156,62 @@ static int inet_diag_fill(struct sk_buff *skb, struct sock *sk,
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int inet_twsk_diag_fill(struct inet_timewait_sock *tw,
|
||||
struct sk_buff *skb, int ext, u32 pid,
|
||||
u32 seq, u16 nlmsg_flags,
|
||||
const struct nlmsghdr *unlh)
|
||||
{
|
||||
long tmo;
|
||||
struct inet_diag_msg *r;
|
||||
const unsigned char *previous_tail = skb->tail;
|
||||
struct nlmsghdr *nlh = NLMSG_PUT(skb, pid, seq,
|
||||
unlh->nlmsg_type, sizeof(*r));
|
||||
|
||||
r = NLMSG_DATA(nlh);
|
||||
BUG_ON(tw->tw_state != TCP_TIME_WAIT);
|
||||
|
||||
nlh->nlmsg_flags = nlmsg_flags;
|
||||
|
||||
tmo = tw->tw_ttd - jiffies;
|
||||
if (tmo < 0)
|
||||
tmo = 0;
|
||||
|
||||
r->idiag_family = tw->tw_family;
|
||||
r->idiag_state = tw->tw_state;
|
||||
r->idiag_timer = 0;
|
||||
r->idiag_retrans = 0;
|
||||
r->id.idiag_if = tw->tw_bound_dev_if;
|
||||
r->id.idiag_cookie[0] = (u32)(unsigned long)tw;
|
||||
r->id.idiag_cookie[1] = (u32)(((unsigned long)tw >> 31) >> 1);
|
||||
r->id.idiag_sport = tw->tw_sport;
|
||||
r->id.idiag_dport = tw->tw_dport;
|
||||
r->id.idiag_src[0] = tw->tw_rcv_saddr;
|
||||
r->id.idiag_dst[0] = tw->tw_daddr;
|
||||
r->idiag_state = tw->tw_substate;
|
||||
r->idiag_timer = 3;
|
||||
r->idiag_expires = (tmo * 1000 + HZ - 1) / HZ;
|
||||
r->idiag_rqueue = 0;
|
||||
r->idiag_wqueue = 0;
|
||||
r->idiag_uid = 0;
|
||||
r->idiag_inode = 0;
|
||||
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
|
||||
if (tw->tw_family == AF_INET6) {
|
||||
const struct inet6_timewait_sock *tw6 =
|
||||
inet6_twsk((struct sock *)tw);
|
||||
|
||||
ipv6_addr_copy((struct in6_addr *)r->id.idiag_src,
|
||||
&tw6->tw_v6_rcv_saddr);
|
||||
ipv6_addr_copy((struct in6_addr *)r->id.idiag_dst,
|
||||
&tw6->tw_v6_daddr);
|
||||
}
|
||||
#endif
|
||||
nlh->nlmsg_len = skb->tail - previous_tail;
|
||||
return skb->len;
|
||||
nlmsg_failure:
|
||||
skb_trim(skb, previous_tail - skb->data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int inet_diag_get_exact(struct sk_buff *in_skb,
|
||||
const struct nlmsghdr *nlh)
|
||||
{
|
||||
|
@ -450,6 +477,42 @@ static int inet_diag_dump_sock(struct sk_buff *skb, struct sock *sk,
|
|||
cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);
|
||||
}
|
||||
|
||||
static int inet_twsk_diag_dump(struct inet_timewait_sock *tw,
|
||||
struct sk_buff *skb,
|
||||
struct netlink_callback *cb)
|
||||
{
|
||||
struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
|
||||
|
||||
if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) {
|
||||
struct inet_diag_entry entry;
|
||||
struct rtattr *bc = (struct rtattr *)(r + 1);
|
||||
|
||||
entry.family = tw->tw_family;
|
||||
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
|
||||
if (tw->tw_family == AF_INET6) {
|
||||
struct inet6_timewait_sock *tw6 =
|
||||
inet6_twsk((struct sock *)tw);
|
||||
entry.saddr = tw6->tw_v6_rcv_saddr.s6_addr32;
|
||||
entry.daddr = tw6->tw_v6_daddr.s6_addr32;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
entry.saddr = &tw->tw_rcv_saddr;
|
||||
entry.daddr = &tw->tw_daddr;
|
||||
}
|
||||
entry.sport = tw->tw_num;
|
||||
entry.dport = ntohs(tw->tw_dport);
|
||||
entry.userlocks = 0;
|
||||
|
||||
if (!inet_diag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), &entry))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return inet_twsk_diag_fill(tw, skb, r->idiag_ext,
|
||||
NETLINK_CB(cb->skb).pid,
|
||||
cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);
|
||||
}
|
||||
|
||||
static int inet_diag_fill_req(struct sk_buff *skb, struct sock *sk,
|
||||
struct request_sock *req, u32 pid, u32 seq,
|
||||
const struct nlmsghdr *unlh)
|
||||
|
@ -696,9 +759,10 @@ static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
}
|
||||
|
||||
if (r->idiag_states & TCPF_TIME_WAIT) {
|
||||
sk_for_each(sk, node,
|
||||
struct inet_timewait_sock *tw;
|
||||
|
||||
inet_twsk_for_each(tw, node,
|
||||
&hashinfo->ehash[i + hashinfo->ehash_size].chain) {
|
||||
const struct inet_timewait_sock *tw = inet_twsk(sk);
|
||||
|
||||
if (num < s_num)
|
||||
goto next_dying;
|
||||
|
@ -708,7 +772,7 @@ static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
if (r->id.idiag_dport != tw->tw_dport &&
|
||||
r->id.idiag_dport)
|
||||
goto next_dying;
|
||||
if (inet_diag_dump_sock(skb, sk, cb) < 0) {
|
||||
if (inet_twsk_diag_dump(tw, skb, cb) < 0) {
|
||||
read_unlock_bh(&head->lock);
|
||||
goto done;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue