Commit 540722ff authored by Arnaldo Carvalho de Melo's avatar Arnaldo Carvalho de Melo Committed by David S. Miller

[TCPDIAG]: Implement cheapest way of supporting DCCPDIAG_GETSOCK

With ugly ifdefs, etc, but this actually:

1. keeps the existing ABI, i.e. no need to recompile the iproute2
   utilities if not interested in DCCP.

2. Provides all the tcp_diag functionality in DCCP, with just a
   small patch that makes iproute2 support DCCP.

Of course I'll get this cleaned-up in time, but for now I think its
OK to be this way to quickly get this functionality.

iproute2-ss050808 patch at:

http://vger.kernel.org/~acme/iproute2-ss050808.dccp.patchSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6687e988
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
/* Just some random number */ /* Just some random number */
#define TCPDIAG_GETSOCK 18 #define TCPDIAG_GETSOCK 18
#define DCCPDIAG_GETSOCK 19
/* Socket identity */ /* Socket identity */
struct tcpdiag_sockid struct tcpdiag_sockid
......
...@@ -34,6 +34,8 @@ struct inet_hashinfo __cacheline_aligned dccp_hashinfo = { ...@@ -34,6 +34,8 @@ struct inet_hashinfo __cacheline_aligned dccp_hashinfo = {
.port_rover = 1024 - 1, .port_rover = 1024 - 1,
}; };
EXPORT_SYMBOL_GPL(dccp_hashinfo);
static int dccp_v4_get_port(struct sock *sk, const unsigned short snum) static int dccp_v4_get_port(struct sock *sk, const unsigned short snum)
{ {
return inet_csk_get_port(&dccp_hashinfo, sk, snum); return inet_csk_get_port(&dccp_hashinfo, sk, snum);
......
...@@ -45,11 +45,15 @@ static struct sock *tcpnl; ...@@ -45,11 +45,15 @@ static struct sock *tcpnl;
#define TCPDIAG_PUT(skb, attrtype, attrlen) \ #define TCPDIAG_PUT(skb, attrtype, attrlen) \
RTA_DATA(__RTA_PUT(skb, attrtype, attrlen)) RTA_DATA(__RTA_PUT(skb, attrtype, attrlen))
#if defined(CONFIG_IP_DCCP) || defined(CONFIG_IP_DCCP_MODULE)
extern struct inet_hashinfo dccp_hashinfo;
#endif
static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk, static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk,
int ext, u32 pid, u32 seq, u16 nlmsg_flags) int ext, u32 pid, u32 seq, u16 nlmsg_flags,
const struct nlmsghdr *unlh)
{ {
const struct inet_sock *inet = inet_sk(sk); const struct inet_sock *inet = inet_sk(sk);
struct tcp_sock *tp = tcp_sk(sk);
const struct inet_connection_sock *icsk = inet_csk(sk); const struct inet_connection_sock *icsk = inet_csk(sk);
struct tcpdiagmsg *r; struct tcpdiagmsg *r;
struct nlmsghdr *nlh; struct nlmsghdr *nlh;
...@@ -57,7 +61,7 @@ static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk, ...@@ -57,7 +61,7 @@ static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk,
struct tcpdiag_meminfo *minfo = NULL; struct tcpdiag_meminfo *minfo = NULL;
unsigned char *b = skb->tail; unsigned char *b = skb->tail;
nlh = NLMSG_PUT(skb, pid, seq, TCPDIAG_GETSOCK, sizeof(*r)); nlh = NLMSG_PUT(skb, pid, seq, unlh->nlmsg_type, sizeof(*r));
nlh->nlmsg_flags = nlmsg_flags; nlh->nlmsg_flags = nlmsg_flags;
r = NLMSG_DATA(nlh); r = NLMSG_DATA(nlh);
if (sk->sk_state != TCP_TIME_WAIT) { if (sk->sk_state != TCP_TIME_WAIT) {
...@@ -147,8 +151,20 @@ static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk, ...@@ -147,8 +151,20 @@ static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk,
r->tcpdiag_expires = 0; r->tcpdiag_expires = 0;
} }
#undef EXPIRES_IN_MS #undef EXPIRES_IN_MS
r->tcpdiag_rqueue = tp->rcv_nxt - tp->copied_seq; /*
r->tcpdiag_wqueue = tp->write_seq - tp->snd_una; * Ahem... for now we'll have some knowledge about TCP -acme
* But this is just one of two small exceptions, both in this
* function, so lets close our eyes for some 15 lines or so... 8)
* -acme
*/
if (sk->sk_protocol == IPPROTO_TCP) {
const struct tcp_sock *tp = tcp_sk(sk);
r->tcpdiag_rqueue = tp->rcv_nxt - tp->copied_seq;
r->tcpdiag_wqueue = tp->write_seq - tp->snd_una;
} else
r->tcpdiag_rqueue = r->tcpdiag_wqueue = 0;
r->tcpdiag_uid = sock_i_uid(sk); r->tcpdiag_uid = sock_i_uid(sk);
r->tcpdiag_inode = sock_i_ino(sk); r->tcpdiag_inode = sock_i_ino(sk);
...@@ -159,8 +175,13 @@ static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk, ...@@ -159,8 +175,13 @@ static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk,
minfo->tcpdiag_tmem = atomic_read(&sk->sk_wmem_alloc); minfo->tcpdiag_tmem = atomic_read(&sk->sk_wmem_alloc);
} }
if (info) /* Ahem... for now we'll have some knowledge about TCP -acme */
tcp_get_info(sk, info); if (info) {
if (sk->sk_protocol == IPPROTO_TCP)
tcp_get_info(sk, info);
else
memset(info, 0, sizeof(*info));
}
if (sk->sk_state < TCP_TIME_WAIT && if (sk->sk_state < TCP_TIME_WAIT &&
icsk->icsk_ca_ops && icsk->icsk_ca_ops->get_info) icsk->icsk_ca_ops && icsk->icsk_ca_ops->get_info)
...@@ -194,9 +215,13 @@ static int tcpdiag_get_exact(struct sk_buff *in_skb, const struct nlmsghdr *nlh) ...@@ -194,9 +215,13 @@ static int tcpdiag_get_exact(struct sk_buff *in_skb, const struct nlmsghdr *nlh)
struct sock *sk; struct sock *sk;
struct tcpdiagreq *req = NLMSG_DATA(nlh); struct tcpdiagreq *req = NLMSG_DATA(nlh);
struct sk_buff *rep; struct sk_buff *rep;
struct inet_hashinfo *hashinfo = &tcp_hashinfo;
#if defined(CONFIG_IP_DCCP) || defined(CONFIG_IP_DCCP_MODULE)
if (nlh->nlmsg_type == DCCPDIAG_GETSOCK)
hashinfo = &dccp_hashinfo;
#endif
if (req->tcpdiag_family == AF_INET) { if (req->tcpdiag_family == AF_INET) {
sk = inet_lookup(&tcp_hashinfo, req->id.tcpdiag_dst[0], sk = inet_lookup(hashinfo, req->id.tcpdiag_dst[0],
req->id.tcpdiag_dport, req->id.tcpdiag_src[0], req->id.tcpdiag_dport, req->id.tcpdiag_src[0],
req->id.tcpdiag_sport, req->id.tcpdiag_if); req->id.tcpdiag_sport, req->id.tcpdiag_if);
} }
...@@ -230,7 +255,7 @@ static int tcpdiag_get_exact(struct sk_buff *in_skb, const struct nlmsghdr *nlh) ...@@ -230,7 +255,7 @@ static int tcpdiag_get_exact(struct sk_buff *in_skb, const struct nlmsghdr *nlh)
if (tcpdiag_fill(rep, sk, req->tcpdiag_ext, if (tcpdiag_fill(rep, sk, req->tcpdiag_ext,
NETLINK_CB(in_skb).pid, NETLINK_CB(in_skb).pid,
nlh->nlmsg_seq, 0) <= 0) nlh->nlmsg_seq, 0, nlh) <= 0)
BUG(); BUG();
err = netlink_unicast(tcpnl, rep, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); err = netlink_unicast(tcpnl, rep, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
...@@ -436,12 +461,13 @@ static int tcpdiag_dump_sock(struct sk_buff *skb, struct sock *sk, ...@@ -436,12 +461,13 @@ static int tcpdiag_dump_sock(struct sk_buff *skb, struct sock *sk,
} }
return tcpdiag_fill(skb, sk, r->tcpdiag_ext, NETLINK_CB(cb->skb).pid, return tcpdiag_fill(skb, sk, r->tcpdiag_ext, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, NLM_F_MULTI); cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);
} }
static int tcpdiag_fill_req(struct sk_buff *skb, struct sock *sk, static int tcpdiag_fill_req(struct sk_buff *skb, struct sock *sk,
struct request_sock *req, struct request_sock *req,
u32 pid, u32 seq) u32 pid, u32 seq,
const struct nlmsghdr *unlh)
{ {
const struct inet_request_sock *ireq = inet_rsk(req); const struct inet_request_sock *ireq = inet_rsk(req);
struct inet_sock *inet = inet_sk(sk); struct inet_sock *inet = inet_sk(sk);
...@@ -450,7 +476,7 @@ static int tcpdiag_fill_req(struct sk_buff *skb, struct sock *sk, ...@@ -450,7 +476,7 @@ static int tcpdiag_fill_req(struct sk_buff *skb, struct sock *sk,
struct nlmsghdr *nlh; struct nlmsghdr *nlh;
long tmo; long tmo;
nlh = NLMSG_PUT(skb, pid, seq, TCPDIAG_GETSOCK, sizeof(*r)); nlh = NLMSG_PUT(skb, pid, seq, unlh->nlmsg_type, sizeof(*r));
nlh->nlmsg_flags = NLM_F_MULTI; nlh->nlmsg_flags = NLM_F_MULTI;
r = NLMSG_DATA(nlh); r = NLMSG_DATA(nlh);
...@@ -526,7 +552,7 @@ static int tcpdiag_dump_reqs(struct sk_buff *skb, struct sock *sk, ...@@ -526,7 +552,7 @@ static int tcpdiag_dump_reqs(struct sk_buff *skb, struct sock *sk,
entry.userlocks = sk->sk_userlocks; entry.userlocks = sk->sk_userlocks;
} }
for (j = s_j; j < TCP_SYNQ_HSIZE; j++) { for (j = s_j; j < lopt->nr_table_entries; j++) {
struct request_sock *req, *head = lopt->syn_table[j]; struct request_sock *req, *head = lopt->syn_table[j];
reqnum = 0; reqnum = 0;
...@@ -561,7 +587,7 @@ static int tcpdiag_dump_reqs(struct sk_buff *skb, struct sock *sk, ...@@ -561,7 +587,7 @@ static int tcpdiag_dump_reqs(struct sk_buff *skb, struct sock *sk,
err = tcpdiag_fill_req(skb, sk, req, err = tcpdiag_fill_req(skb, sk, req,
NETLINK_CB(cb->skb).pid, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq); cb->nlh->nlmsg_seq, cb->nlh);
if (err < 0) { if (err < 0) {
cb->args[3] = j + 1; cb->args[3] = j + 1;
cb->args[4] = reqnum; cb->args[4] = reqnum;
...@@ -583,20 +609,26 @@ static int tcpdiag_dump(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -583,20 +609,26 @@ static int tcpdiag_dump(struct sk_buff *skb, struct netlink_callback *cb)
int i, num; int i, num;
int s_i, s_num; int s_i, s_num;
struct tcpdiagreq *r = NLMSG_DATA(cb->nlh); struct tcpdiagreq *r = NLMSG_DATA(cb->nlh);
struct inet_hashinfo *hashinfo;
s_i = cb->args[1]; s_i = cb->args[1];
s_num = num = cb->args[2]; s_num = num = cb->args[2];
hashinfo = &tcp_hashinfo;
#if defined(CONFIG_IP_DCCP) || defined(CONFIG_IP_DCCP_MODULE)
if (cb->nlh->nlmsg_type == DCCPDIAG_GETSOCK)
hashinfo = &dccp_hashinfo;
#endif
if (cb->args[0] == 0) { if (cb->args[0] == 0) {
if (!(r->tcpdiag_states&(TCPF_LISTEN|TCPF_SYN_RECV))) if (!(r->tcpdiag_states&(TCPF_LISTEN|TCPF_SYN_RECV)))
goto skip_listen_ht; goto skip_listen_ht;
inet_listen_lock(&tcp_hashinfo);
inet_listen_lock(hashinfo);
for (i = s_i; i < INET_LHTABLE_SIZE; i++) { for (i = s_i; i < INET_LHTABLE_SIZE; i++) {
struct sock *sk; struct sock *sk;
struct hlist_node *node; struct hlist_node *node;
num = 0; num = 0;
sk_for_each(sk, node, &tcp_hashinfo.listening_hash[i]) { sk_for_each(sk, node, &hashinfo->listening_hash[i]) {
struct inet_sock *inet = inet_sk(sk); struct inet_sock *inet = inet_sk(sk);
if (num < s_num) { if (num < s_num) {
...@@ -614,7 +646,7 @@ static int tcpdiag_dump(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -614,7 +646,7 @@ static int tcpdiag_dump(struct sk_buff *skb, struct netlink_callback *cb)
goto syn_recv; goto syn_recv;
if (tcpdiag_dump_sock(skb, sk, cb) < 0) { if (tcpdiag_dump_sock(skb, sk, cb) < 0) {
inet_listen_unlock(&tcp_hashinfo); inet_listen_unlock(hashinfo);
goto done; goto done;
} }
...@@ -623,7 +655,7 @@ syn_recv: ...@@ -623,7 +655,7 @@ syn_recv:
goto next_listen; goto next_listen;
if (tcpdiag_dump_reqs(skb, sk, cb) < 0) { if (tcpdiag_dump_reqs(skb, sk, cb) < 0) {
inet_listen_unlock(&tcp_hashinfo); inet_listen_unlock(hashinfo);
goto done; goto done;
} }
...@@ -637,7 +669,7 @@ next_listen: ...@@ -637,7 +669,7 @@ next_listen:
cb->args[3] = 0; cb->args[3] = 0;
cb->args[4] = 0; cb->args[4] = 0;
} }
inet_listen_unlock(&tcp_hashinfo); inet_listen_unlock(hashinfo);
skip_listen_ht: skip_listen_ht:
cb->args[0] = 1; cb->args[0] = 1;
s_i = num = s_num = 0; s_i = num = s_num = 0;
...@@ -646,8 +678,8 @@ skip_listen_ht: ...@@ -646,8 +678,8 @@ skip_listen_ht:
if (!(r->tcpdiag_states&~(TCPF_LISTEN|TCPF_SYN_RECV))) if (!(r->tcpdiag_states&~(TCPF_LISTEN|TCPF_SYN_RECV)))
return skb->len; return skb->len;
for (i = s_i; i < tcp_hashinfo.ehash_size; i++) { for (i = s_i; i < hashinfo->ehash_size; i++) {
struct inet_ehash_bucket *head = &tcp_hashinfo.ehash[i]; struct inet_ehash_bucket *head = &hashinfo->ehash[i];
struct sock *sk; struct sock *sk;
struct hlist_node *node; struct hlist_node *node;
...@@ -679,7 +711,7 @@ next_normal: ...@@ -679,7 +711,7 @@ next_normal:
if (r->tcpdiag_states&TCPF_TIME_WAIT) { if (r->tcpdiag_states&TCPF_TIME_WAIT) {
sk_for_each(sk, node, sk_for_each(sk, node,
&tcp_hashinfo.ehash[i + tcp_hashinfo.ehash_size].chain) { &hashinfo->ehash[i + hashinfo->ehash_size].chain) {
struct inet_sock *inet = inet_sk(sk); struct inet_sock *inet = inet_sk(sk);
if (num < s_num) if (num < s_num)
...@@ -719,7 +751,11 @@ tcpdiag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) ...@@ -719,7 +751,11 @@ tcpdiag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
if (!(nlh->nlmsg_flags&NLM_F_REQUEST)) if (!(nlh->nlmsg_flags&NLM_F_REQUEST))
return 0; return 0;
if (nlh->nlmsg_type != TCPDIAG_GETSOCK) if (nlh->nlmsg_type != TCPDIAG_GETSOCK
#if defined(CONFIG_IP_DCCP) || defined(CONFIG_IP_DCCP_MODULE)
&& nlh->nlmsg_type != DCCPDIAG_GETSOCK
#endif
)
goto err_inval; goto err_inval;
if (NLMSG_LENGTH(sizeof(struct tcpdiagreq)) > skb->len) if (NLMSG_LENGTH(sizeof(struct tcpdiagreq)) > skb->len)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment