Skip to content

Commit c7d58aa

Browse files
Arnaldo Carvalho de Melodavem330
authored andcommitted
[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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 4e852c0 commit c7d58aa

File tree

1 file changed

+111
-47
lines changed

1 file changed

+111
-47
lines changed

net/ipv4/inet_diag.c

Lines changed: 111 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -70,20 +70,22 @@ static int inet_diag_fill(struct sk_buff *skb, struct sock *sk,
7070
nlh->nlmsg_flags = nlmsg_flags;
7171

7272
r = NLMSG_DATA(nlh);
73-
if (sk->sk_state != TCP_TIME_WAIT) {
74-
if (ext & (1 << (INET_DIAG_MEMINFO - 1)))
75-
minfo = INET_DIAG_PUT(skb, INET_DIAG_MEMINFO,
76-
sizeof(*minfo));
77-
if (ext & (1 << (INET_DIAG_INFO - 1)))
78-
info = INET_DIAG_PUT(skb, INET_DIAG_INFO,
79-
handler->idiag_info_size);
80-
81-
if ((ext & (1 << (INET_DIAG_CONG - 1))) && icsk->icsk_ca_ops) {
82-
size_t len = strlen(icsk->icsk_ca_ops->name);
83-
strcpy(INET_DIAG_PUT(skb, INET_DIAG_CONG, len + 1),
84-
icsk->icsk_ca_ops->name);
85-
}
73+
BUG_ON(sk->sk_state == TCP_TIME_WAIT);
74+
75+
if (ext & (1 << (INET_DIAG_MEMINFO - 1)))
76+
minfo = INET_DIAG_PUT(skb, INET_DIAG_MEMINFO, sizeof(*minfo));
77+
78+
if (ext & (1 << (INET_DIAG_INFO - 1)))
79+
info = INET_DIAG_PUT(skb, INET_DIAG_INFO,
80+
handler->idiag_info_size);
81+
82+
if ((ext & (1 << (INET_DIAG_CONG - 1))) && icsk->icsk_ca_ops) {
83+
const size_t len = strlen(icsk->icsk_ca_ops->name);
84+
85+
strcpy(INET_DIAG_PUT(skb, INET_DIAG_CONG, len + 1),
86+
icsk->icsk_ca_ops->name);
8687
}
88+
8789
r->idiag_family = sk->sk_family;
8890
r->idiag_state = sk->sk_state;
8991
r->idiag_timer = 0;
@@ -93,37 +95,6 @@ static int inet_diag_fill(struct sk_buff *skb, struct sock *sk,
9395
r->id.idiag_cookie[0] = (u32)(unsigned long)sk;
9496
r->id.idiag_cookie[1] = (u32)(((unsigned long)sk >> 31) >> 1);
9597

96-
if (r->idiag_state == TCP_TIME_WAIT) {
97-
const struct inet_timewait_sock *tw = inet_twsk(sk);
98-
long tmo = tw->tw_ttd - jiffies;
99-
if (tmo < 0)
100-
tmo = 0;
101-
102-
r->id.idiag_sport = tw->tw_sport;
103-
r->id.idiag_dport = tw->tw_dport;
104-
r->id.idiag_src[0] = tw->tw_rcv_saddr;
105-
r->id.idiag_dst[0] = tw->tw_daddr;
106-
r->idiag_state = tw->tw_substate;
107-
r->idiag_timer = 3;
108-
r->idiag_expires = (tmo * 1000 + HZ - 1) / HZ;
109-
r->idiag_rqueue = 0;
110-
r->idiag_wqueue = 0;
111-
r->idiag_uid = 0;
112-
r->idiag_inode = 0;
113-
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
114-
if (r->idiag_family == AF_INET6) {
115-
const struct inet6_timewait_sock *tw6 = inet6_twsk(sk);
116-
117-
ipv6_addr_copy((struct in6_addr *)r->id.idiag_src,
118-
&tw6->tw_v6_rcv_saddr);
119-
ipv6_addr_copy((struct in6_addr *)r->id.idiag_dst,
120-
&tw6->tw_v6_daddr);
121-
}
122-
#endif
123-
nlh->nlmsg_len = skb->tail - b;
124-
return skb->len;
125-
}
126-
12798
r->id.idiag_sport = inet->sport;
12899
r->id.idiag_dport = inet->dport;
129100
r->id.idiag_src[0] = inet->rcv_saddr;
@@ -185,6 +156,62 @@ static int inet_diag_fill(struct sk_buff *skb, struct sock *sk,
185156
return -1;
186157
}
187158

159+
static int inet_twsk_diag_fill(struct inet_timewait_sock *tw,
160+
struct sk_buff *skb, int ext, u32 pid,
161+
u32 seq, u16 nlmsg_flags,
162+
const struct nlmsghdr *unlh)
163+
{
164+
long tmo;
165+
struct inet_diag_msg *r;
166+
const unsigned char *previous_tail = skb->tail;
167+
struct nlmsghdr *nlh = NLMSG_PUT(skb, pid, seq,
168+
unlh->nlmsg_type, sizeof(*r));
169+
170+
r = NLMSG_DATA(nlh);
171+
BUG_ON(tw->tw_state != TCP_TIME_WAIT);
172+
173+
nlh->nlmsg_flags = nlmsg_flags;
174+
175+
tmo = tw->tw_ttd - jiffies;
176+
if (tmo < 0)
177+
tmo = 0;
178+
179+
r->idiag_family = tw->tw_family;
180+
r->idiag_state = tw->tw_state;
181+
r->idiag_timer = 0;
182+
r->idiag_retrans = 0;
183+
r->id.idiag_if = tw->tw_bound_dev_if;
184+
r->id.idiag_cookie[0] = (u32)(unsigned long)tw;
185+
r->id.idiag_cookie[1] = (u32)(((unsigned long)tw >> 31) >> 1);
186+
r->id.idiag_sport = tw->tw_sport;
187+
r->id.idiag_dport = tw->tw_dport;
188+
r->id.idiag_src[0] = tw->tw_rcv_saddr;
189+
r->id.idiag_dst[0] = tw->tw_daddr;
190+
r->idiag_state = tw->tw_substate;
191+
r->idiag_timer = 3;
192+
r->idiag_expires = (tmo * 1000 + HZ - 1) / HZ;
193+
r->idiag_rqueue = 0;
194+
r->idiag_wqueue = 0;
195+
r->idiag_uid = 0;
196+
r->idiag_inode = 0;
197+
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
198+
if (tw->tw_family == AF_INET6) {
199+
const struct inet6_timewait_sock *tw6 =
200+
inet6_twsk((struct sock *)tw);
201+
202+
ipv6_addr_copy((struct in6_addr *)r->id.idiag_src,
203+
&tw6->tw_v6_rcv_saddr);
204+
ipv6_addr_copy((struct in6_addr *)r->id.idiag_dst,
205+
&tw6->tw_v6_daddr);
206+
}
207+
#endif
208+
nlh->nlmsg_len = skb->tail - previous_tail;
209+
return skb->len;
210+
nlmsg_failure:
211+
skb_trim(skb, previous_tail - skb->data);
212+
return -1;
213+
}
214+
188215
static int inet_diag_get_exact(struct sk_buff *in_skb,
189216
const struct nlmsghdr *nlh)
190217
{
@@ -450,6 +477,42 @@ static int inet_diag_dump_sock(struct sk_buff *skb, struct sock *sk,
450477
cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);
451478
}
452479

480+
static int inet_twsk_diag_dump(struct inet_timewait_sock *tw,
481+
struct sk_buff *skb,
482+
struct netlink_callback *cb)
483+
{
484+
struct inet_diag_req *r = NLMSG_DATA(cb->nlh);
485+
486+
if (cb->nlh->nlmsg_len > 4 + NLMSG_SPACE(sizeof(*r))) {
487+
struct inet_diag_entry entry;
488+
struct rtattr *bc = (struct rtattr *)(r + 1);
489+
490+
entry.family = tw->tw_family;
491+
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
492+
if (tw->tw_family == AF_INET6) {
493+
struct inet6_timewait_sock *tw6 =
494+
inet6_twsk((struct sock *)tw);
495+
entry.saddr = tw6->tw_v6_rcv_saddr.s6_addr32;
496+
entry.daddr = tw6->tw_v6_daddr.s6_addr32;
497+
} else
498+
#endif
499+
{
500+
entry.saddr = &tw->tw_rcv_saddr;
501+
entry.daddr = &tw->tw_daddr;
502+
}
503+
entry.sport = tw->tw_num;
504+
entry.dport = ntohs(tw->tw_dport);
505+
entry.userlocks = 0;
506+
507+
if (!inet_diag_bc_run(RTA_DATA(bc), RTA_PAYLOAD(bc), &entry))
508+
return 0;
509+
}
510+
511+
return inet_twsk_diag_fill(tw, skb, r->idiag_ext,
512+
NETLINK_CB(cb->skb).pid,
513+
cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);
514+
}
515+
453516
static int inet_diag_fill_req(struct sk_buff *skb, struct sock *sk,
454517
struct request_sock *req, u32 pid, u32 seq,
455518
const struct nlmsghdr *unlh)
@@ -696,9 +759,10 @@ static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
696759
}
697760

698761
if (r->idiag_states & TCPF_TIME_WAIT) {
699-
sk_for_each(sk, node,
762+
struct inet_timewait_sock *tw;
763+
764+
inet_twsk_for_each(tw, node,
700765
&hashinfo->ehash[i + hashinfo->ehash_size].chain) {
701-
const struct inet_timewait_sock *tw = inet_twsk(sk);
702766

703767
if (num < s_num)
704768
goto next_dying;
@@ -708,7 +772,7 @@ static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
708772
if (r->id.idiag_dport != tw->tw_dport &&
709773
r->id.idiag_dport)
710774
goto next_dying;
711-
if (inet_diag_dump_sock(skb, sk, cb) < 0) {
775+
if (inet_twsk_diag_dump(tw, skb, cb) < 0) {
712776
read_unlock_bh(&head->lock);
713777
goto done;
714778
}

0 commit comments

Comments
 (0)