Skip to content

Commit 3ad88cf

Browse files
Christoph Paaschdavem330
authored andcommitted
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>
1 parent 5ae5e99 commit 3ad88cf

File tree

1 file changed

+40
-24
lines changed

1 file changed

+40
-24
lines changed

net/ipv4/tcp_metrics.c

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -274,24 +274,32 @@ static struct tcp_metrics_block *__tcp_get_metrics_tw(struct inet_timewait_sock
274274
unsigned int hash;
275275
struct net *net;
276276

277-
saddr.family = tw->tw_family;
278-
daddr.family = tw->tw_family;
279-
switch (daddr.family) {
280-
case AF_INET:
277+
if (tw->tw_family == AF_INET) {
278+
saddr.family = AF_INET;
281279
saddr.addr.a4 = tw->tw_rcv_saddr;
280+
daddr.family = AF_INET;
282281
daddr.addr.a4 = tw->tw_daddr;
283282
hash = (__force unsigned int) daddr.addr.a4;
284-
break;
283+
}
285284
#if IS_ENABLED(CONFIG_IPV6)
286-
case AF_INET6:
287-
*(struct in6_addr *)saddr.addr.a6 = tw->tw_v6_rcv_saddr;
288-
*(struct in6_addr *)daddr.addr.a6 = tw->tw_v6_daddr;
289-
hash = ipv6_addr_hash(&tw->tw_v6_daddr);
290-
break;
285+
else if (tw->tw_family == AF_INET6) {
286+
if (ipv6_addr_v4mapped(&tw->tw_v6_daddr)) {
287+
saddr.family = AF_INET;
288+
saddr.addr.a4 = tw->tw_rcv_saddr;
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+
}
291300
#endif
292-
default:
301+
else
293302
return NULL;
294-
}
295303

296304
net = twsk_net(tw);
297305
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,
314322
unsigned int hash;
315323
struct net *net;
316324

317-
saddr.family = sk->sk_family;
318-
daddr.family = sk->sk_family;
319-
switch (daddr.family) {
320-
case AF_INET:
325+
if (sk->sk_family == AF_INET) {
326+
saddr.family = AF_INET;
321327
saddr.addr.a4 = inet_sk(sk)->inet_saddr;
328+
daddr.family = AF_INET;
322329
daddr.addr.a4 = inet_sk(sk)->inet_daddr;
323330
hash = (__force unsigned int) daddr.addr.a4;
324-
break;
331+
}
325332
#if IS_ENABLED(CONFIG_IPV6)
326-
case AF_INET6:
327-
*(struct in6_addr *)saddr.addr.a6 = sk->sk_v6_rcv_saddr;
328-
*(struct in6_addr *)daddr.addr.a6 = sk->sk_v6_daddr;
329-
hash = ipv6_addr_hash(&sk->sk_v6_daddr);
330-
break;
333+
else if (sk->sk_family == AF_INET6) {
334+
if (ipv6_addr_v4mapped(&sk->sk_v6_daddr)) {
335+
saddr.family = AF_INET;
336+
saddr.addr.a4 = inet_sk(sk)->inet_saddr;
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+
}
331348
#endif
332-
default:
349+
else
333350
return NULL;
334-
}
335351

336352
net = dev_net(dst->dev);
337353
hash = hash_32(hash, net->ipv4.tcp_metrics_hash_log);

0 commit comments

Comments
 (0)