aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorChristoph Paasch <christoph.paasch@uclouvain.be>2014-01-22 07:58:44 -0500
committerDavid S. Miller <davem@davemloft.net>2014-01-23 15:48:28 -0500
commit3ad88cf70af79e6f19c4f89dd85453ba4fdf425e (patch)
tree3717f53d734cecb7945638846f19477dad3ea8d0 /net
parent5ae5e991ee6274cc269dabd536399146be038a0f (diff)
tcp: metrics: Handle v6/v4-mapped sockets in tcp-metrics
A socket may be v6/v4-mapped. In that case sk->sk_family is AF_INET6, but the IP being used is actually an IPv4-address. Current's tcp-metrics will thus represent it as an IPv6-address: root@server:~# ip tcp_metrics ::ffff:10.1.1.2 age 22.920sec rtt 18750us rttvar 15000us cwnd 10 10.1.1.2 age 47.970sec rtt 16250us rttvar 10000us cwnd 10 This patch modifies the tcp-metrics so that they are able to handle the v6/v4-mapped sockets correctly. Signed-off-by: Christoph Paasch <christoph.paasch@uclouvain.be> Acked-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/tcp_metrics.c64
1 files changed, 40 insertions, 24 deletions
diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c
index 9ae48b4a37d1..d547075d8300 100644
--- a/net/ipv4/tcp_metrics.c
+++ b/net/ipv4/tcp_metrics.c
@@ -274,24 +274,32 @@ static struct tcp_metrics_block *__tcp_get_metrics_tw(struct inet_timewait_sock
274 unsigned int hash; 274 unsigned int hash;
275 struct net *net; 275 struct net *net;
276 276
277 saddr.family = tw->tw_family; 277 if (tw->tw_family == AF_INET) {
278 daddr.family = tw->tw_family; 278 saddr.family = AF_INET;
279 switch (daddr.family) {
280 case AF_INET:
281 saddr.addr.a4 = tw->tw_rcv_saddr; 279 saddr.addr.a4 = tw->tw_rcv_saddr;
280 daddr.family = AF_INET;
282 daddr.addr.a4 = tw->tw_daddr; 281 daddr.addr.a4 = tw->tw_daddr;
283 hash = (__force unsigned int) daddr.addr.a4; 282 hash = (__force unsigned int) daddr.addr.a4;
284 break; 283 }
285#if IS_ENABLED(CONFIG_IPV6) 284#if IS_ENABLED(CONFIG_IPV6)
286 case AF_INET6: 285 else if (tw->tw_family == AF_INET6) {
287 *(struct in6_addr *)saddr.addr.a6 = tw->tw_v6_rcv_saddr; 286 if (ipv6_addr_v4mapped(&tw->tw_v6_daddr)) {
288 *(struct in6_addr *)daddr.addr.a6 = tw->tw_v6_daddr; 287 saddr.family = AF_INET;
289 hash = ipv6_addr_hash(&tw->tw_v6_daddr); 288 saddr.addr.a4 = tw->tw_rcv_saddr;
290 break; 289 daddr.family = AF_INET;
290 daddr.addr.a4 = tw->tw_daddr;
291 hash = (__force unsigned int) daddr.addr.a4;
292 } else {
293 saddr.family = AF_INET6;
294 *(struct in6_addr *)saddr.addr.a6 = tw->tw_v6_rcv_saddr;
295 daddr.family = AF_INET6;
296 *(struct in6_addr *)daddr.addr.a6 = tw->tw_v6_daddr;
297 hash = ipv6_addr_hash(&tw->tw_v6_daddr);
298 }
299 }
291#endif 300#endif
292 default: 301 else
293 return NULL; 302 return NULL;
294 }
295 303
296 net = twsk_net(tw); 304 net = twsk_net(tw);
297 hash = hash_32(hash, net->ipv4.tcp_metrics_hash_log); 305 hash = hash_32(hash, net->ipv4.tcp_metrics_hash_log);
@@ -314,24 +322,32 @@ static struct tcp_metrics_block *tcp_get_metrics(struct sock *sk,
314 unsigned int hash; 322 unsigned int hash;
315 struct net *net; 323 struct net *net;
316 324
317 saddr.family = sk->sk_family; 325 if (sk->sk_family == AF_INET) {
318 daddr.family = sk->sk_family; 326 saddr.family = AF_INET;
319 switch (daddr.family) {
320 case AF_INET:
321 saddr.addr.a4 = inet_sk(sk)->inet_saddr; 327 saddr.addr.a4 = inet_sk(sk)->inet_saddr;
328 daddr.family = AF_INET;
322 daddr.addr.a4 = inet_sk(sk)->inet_daddr; 329 daddr.addr.a4 = inet_sk(sk)->inet_daddr;
323 hash = (__force unsigned int) daddr.addr.a4; 330 hash = (__force unsigned int) daddr.addr.a4;
324 break; 331 }
325#if IS_ENABLED(CONFIG_IPV6) 332#if IS_ENABLED(CONFIG_IPV6)
326 case AF_INET6: 333 else if (sk->sk_family == AF_INET6) {
327 *(struct in6_addr *)saddr.addr.a6 = sk->sk_v6_rcv_saddr; 334 if (ipv6_addr_v4mapped(&sk->sk_v6_daddr)) {
328 *(struct in6_addr *)daddr.addr.a6 = sk->sk_v6_daddr; 335 saddr.family = AF_INET;
329 hash = ipv6_addr_hash(&sk->sk_v6_daddr); 336 saddr.addr.a4 = inet_sk(sk)->inet_saddr;
330 break; 337 daddr.family = AF_INET;
338 daddr.addr.a4 = inet_sk(sk)->inet_daddr;
339 hash = (__force unsigned int) daddr.addr.a4;
340 } else {
341 saddr.family = AF_INET6;
342 *(struct in6_addr *)saddr.addr.a6 = sk->sk_v6_rcv_saddr;
343 daddr.family = AF_INET6;
344 *(struct in6_addr *)daddr.addr.a6 = sk->sk_v6_daddr;
345 hash = ipv6_addr_hash(&sk->sk_v6_daddr);
346 }
347 }
331#endif 348#endif
332 default: 349 else
333 return NULL; 350 return NULL;
334 }
335 351
336 net = dev_net(dst->dev); 352 net = dev_net(dst->dev);
337 hash = hash_32(hash, net->ipv4.tcp_metrics_hash_log); 353 hash = hash_32(hash, net->ipv4.tcp_metrics_hash_log);