aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_metrics.c
diff options
context:
space:
mode:
authorChristoph Paasch <christoph.paasch@uclouvain.be>2014-01-08 10:05:56 -0500
committerDavid S. Miller <davem@davemloft.net>2014-01-10 17:38:18 -0500
commita544302820db12660b15de185b9e67c781a6b74e (patch)
tree3eb9015f85c1adfc7bf43c40b197b7f12c8d38a4 /net/ipv4/tcp_metrics.c
parent324fd55a19827b7191cc6ab73865e30c0e6e6423 (diff)
tcp: metrics: Add source-address to tcp-metrics
We add the source-address to the tcp-metrics, so that different metrics will be used per source/destination-pair. We use the destination-hash to store the metric inside the hash-table. That way, deleting and dumping via "ip tcp_metrics" is easy. Signed-off-by: Christoph Paasch <christoph.paasch@uclouvain.be> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/tcp_metrics.c')
-rw-r--r--net/ipv4/tcp_metrics.c34
1 files changed, 25 insertions, 9 deletions
diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c
index f9b5f519a4ea..de32aa41a846 100644
--- a/net/ipv4/tcp_metrics.c
+++ b/net/ipv4/tcp_metrics.c
@@ -31,6 +31,7 @@ struct tcp_fastopen_metrics {
31 31
32struct tcp_metrics_block { 32struct tcp_metrics_block {
33 struct tcp_metrics_block __rcu *tcpm_next; 33 struct tcp_metrics_block __rcu *tcpm_next;
34 struct inetpeer_addr tcpm_saddr;
34 struct inetpeer_addr tcpm_daddr; 35 struct inetpeer_addr tcpm_daddr;
35 unsigned long tcpm_stamp; 36 unsigned long tcpm_stamp;
36 u32 tcpm_ts; 37 u32 tcpm_ts;
@@ -131,6 +132,7 @@ static void tcpm_suck_dst(struct tcp_metrics_block *tm, struct dst_entry *dst,
131} 132}
132 133
133static struct tcp_metrics_block *tcpm_new(struct dst_entry *dst, 134static struct tcp_metrics_block *tcpm_new(struct dst_entry *dst,
135 struct inetpeer_addr *saddr,
134 struct inetpeer_addr *daddr, 136 struct inetpeer_addr *daddr,
135 unsigned int hash, 137 unsigned int hash,
136 bool reclaim) 138 bool reclaim)
@@ -155,6 +157,7 @@ static struct tcp_metrics_block *tcpm_new(struct dst_entry *dst,
155 if (!tm) 157 if (!tm)
156 goto out_unlock; 158 goto out_unlock;
157 } 159 }
160 tm->tcpm_saddr = *saddr;
158 tm->tcpm_daddr = *daddr; 161 tm->tcpm_daddr = *daddr;
159 162
160 tcpm_suck_dst(tm, dst, true); 163 tcpm_suck_dst(tm, dst, true);
@@ -189,7 +192,8 @@ static struct tcp_metrics_block *tcp_get_encode(struct tcp_metrics_block *tm, in
189 return NULL; 192 return NULL;
190} 193}
191 194
192static struct tcp_metrics_block *__tcp_get_metrics(const struct inetpeer_addr *daddr, 195static struct tcp_metrics_block *__tcp_get_metrics(const struct inetpeer_addr *saddr,
196 const struct inetpeer_addr *daddr,
193 struct net *net, unsigned int hash) 197 struct net *net, unsigned int hash)
194{ 198{
195 struct tcp_metrics_block *tm; 199 struct tcp_metrics_block *tm;
@@ -197,7 +201,8 @@ static struct tcp_metrics_block *__tcp_get_metrics(const struct inetpeer_addr *d
197 201
198 for (tm = rcu_dereference(net->ipv4.tcp_metrics_hash[hash].chain); tm; 202 for (tm = rcu_dereference(net->ipv4.tcp_metrics_hash[hash].chain); tm;
199 tm = rcu_dereference(tm->tcpm_next)) { 203 tm = rcu_dereference(tm->tcpm_next)) {
200 if (addr_same(&tm->tcpm_daddr, daddr)) 204 if (addr_same(&tm->tcpm_saddr, saddr) &&
205 addr_same(&tm->tcpm_daddr, daddr))
201 break; 206 break;
202 depth++; 207 depth++;
203 } 208 }
@@ -208,18 +213,21 @@ static struct tcp_metrics_block *__tcp_get_metrics_req(struct request_sock *req,
208 struct dst_entry *dst) 213 struct dst_entry *dst)
209{ 214{
210 struct tcp_metrics_block *tm; 215 struct tcp_metrics_block *tm;
211 struct inetpeer_addr daddr; 216 struct inetpeer_addr saddr, daddr;
212 unsigned int hash; 217 unsigned int hash;
213 struct net *net; 218 struct net *net;
214 219
220 saddr.family = req->rsk_ops->family;
215 daddr.family = req->rsk_ops->family; 221 daddr.family = req->rsk_ops->family;
216 switch (daddr.family) { 222 switch (daddr.family) {
217 case AF_INET: 223 case AF_INET:
224 saddr.addr.a4 = inet_rsk(req)->ir_loc_addr;
218 daddr.addr.a4 = inet_rsk(req)->ir_rmt_addr; 225 daddr.addr.a4 = inet_rsk(req)->ir_rmt_addr;
219 hash = (__force unsigned int) daddr.addr.a4; 226 hash = (__force unsigned int) daddr.addr.a4;
220 break; 227 break;
221#if IS_ENABLED(CONFIG_IPV6) 228#if IS_ENABLED(CONFIG_IPV6)
222 case AF_INET6: 229 case AF_INET6:
230 *(struct in6_addr *)saddr.addr.a6 = inet_rsk(req)->ir_v6_loc_addr;
223 *(struct in6_addr *)daddr.addr.a6 = inet_rsk(req)->ir_v6_rmt_addr; 231 *(struct in6_addr *)daddr.addr.a6 = inet_rsk(req)->ir_v6_rmt_addr;
224 hash = ipv6_addr_hash(&inet_rsk(req)->ir_v6_rmt_addr); 232 hash = ipv6_addr_hash(&inet_rsk(req)->ir_v6_rmt_addr);
225 break; 233 break;
@@ -233,7 +241,8 @@ static struct tcp_metrics_block *__tcp_get_metrics_req(struct request_sock *req,
233 241
234 for (tm = rcu_dereference(net->ipv4.tcp_metrics_hash[hash].chain); tm; 242 for (tm = rcu_dereference(net->ipv4.tcp_metrics_hash[hash].chain); tm;
235 tm = rcu_dereference(tm->tcpm_next)) { 243 tm = rcu_dereference(tm->tcpm_next)) {
236 if (addr_same(&tm->tcpm_daddr, &daddr)) 244 if (addr_same(&tm->tcpm_saddr, &saddr) &&
245 addr_same(&tm->tcpm_daddr, &daddr))
237 break; 246 break;
238 } 247 }
239 tcpm_check_stamp(tm, dst); 248 tcpm_check_stamp(tm, dst);
@@ -243,18 +252,21 @@ static struct tcp_metrics_block *__tcp_get_metrics_req(struct request_sock *req,
243static struct tcp_metrics_block *__tcp_get_metrics_tw(struct inet_timewait_sock *tw) 252static struct tcp_metrics_block *__tcp_get_metrics_tw(struct inet_timewait_sock *tw)
244{ 253{
245 struct tcp_metrics_block *tm; 254 struct tcp_metrics_block *tm;
246 struct inetpeer_addr daddr; 255 struct inetpeer_addr saddr, daddr;
247 unsigned int hash; 256 unsigned int hash;
248 struct net *net; 257 struct net *net;
249 258
259 saddr.family = tw->tw_family;
250 daddr.family = tw->tw_family; 260 daddr.family = tw->tw_family;
251 switch (daddr.family) { 261 switch (daddr.family) {
252 case AF_INET: 262 case AF_INET:
263 saddr.addr.a4 = tw->tw_rcv_saddr;
253 daddr.addr.a4 = tw->tw_daddr; 264 daddr.addr.a4 = tw->tw_daddr;
254 hash = (__force unsigned int) daddr.addr.a4; 265 hash = (__force unsigned int) daddr.addr.a4;
255 break; 266 break;
256#if IS_ENABLED(CONFIG_IPV6) 267#if IS_ENABLED(CONFIG_IPV6)
257 case AF_INET6: 268 case AF_INET6:
269 *(struct in6_addr *)saddr.addr.a6 = tw->tw_v6_rcv_saddr;
258 *(struct in6_addr *)daddr.addr.a6 = tw->tw_v6_daddr; 270 *(struct in6_addr *)daddr.addr.a6 = tw->tw_v6_daddr;
259 hash = ipv6_addr_hash(&tw->tw_v6_daddr); 271 hash = ipv6_addr_hash(&tw->tw_v6_daddr);
260 break; 272 break;
@@ -268,7 +280,8 @@ static struct tcp_metrics_block *__tcp_get_metrics_tw(struct inet_timewait_sock
268 280
269 for (tm = rcu_dereference(net->ipv4.tcp_metrics_hash[hash].chain); tm; 281 for (tm = rcu_dereference(net->ipv4.tcp_metrics_hash[hash].chain); tm;
270 tm = rcu_dereference(tm->tcpm_next)) { 282 tm = rcu_dereference(tm->tcpm_next)) {
271 if (addr_same(&tm->tcpm_daddr, &daddr)) 283 if (addr_same(&tm->tcpm_saddr, &saddr) &&
284 addr_same(&tm->tcpm_daddr, &daddr))
272 break; 285 break;
273 } 286 }
274 return tm; 287 return tm;
@@ -279,19 +292,22 @@ static struct tcp_metrics_block *tcp_get_metrics(struct sock *sk,
279 bool create) 292 bool create)
280{ 293{
281 struct tcp_metrics_block *tm; 294 struct tcp_metrics_block *tm;
282 struct inetpeer_addr daddr; 295 struct inetpeer_addr saddr, daddr;
283 unsigned int hash; 296 unsigned int hash;
284 struct net *net; 297 struct net *net;
285 bool reclaim; 298 bool reclaim;
286 299
300 saddr.family = sk->sk_family;
287 daddr.family = sk->sk_family; 301 daddr.family = sk->sk_family;
288 switch (daddr.family) { 302 switch (daddr.family) {
289 case AF_INET: 303 case AF_INET:
304 saddr.addr.a4 = inet_sk(sk)->inet_saddr;
290 daddr.addr.a4 = inet_sk(sk)->inet_daddr; 305 daddr.addr.a4 = inet_sk(sk)->inet_daddr;
291 hash = (__force unsigned int) daddr.addr.a4; 306 hash = (__force unsigned int) daddr.addr.a4;
292 break; 307 break;
293#if IS_ENABLED(CONFIG_IPV6) 308#if IS_ENABLED(CONFIG_IPV6)
294 case AF_INET6: 309 case AF_INET6:
310 *(struct in6_addr *)saddr.addr.a6 = sk->sk_v6_rcv_saddr;
295 *(struct in6_addr *)daddr.addr.a6 = sk->sk_v6_daddr; 311 *(struct in6_addr *)daddr.addr.a6 = sk->sk_v6_daddr;
296 hash = ipv6_addr_hash(&sk->sk_v6_daddr); 312 hash = ipv6_addr_hash(&sk->sk_v6_daddr);
297 break; 313 break;
@@ -303,14 +319,14 @@ static struct tcp_metrics_block *tcp_get_metrics(struct sock *sk,
303 net = dev_net(dst->dev); 319 net = dev_net(dst->dev);
304 hash = hash_32(hash, net->ipv4.tcp_metrics_hash_log); 320 hash = hash_32(hash, net->ipv4.tcp_metrics_hash_log);
305 321
306 tm = __tcp_get_metrics(&daddr, net, hash); 322 tm = __tcp_get_metrics(&saddr, &daddr, net, hash);
307 reclaim = false; 323 reclaim = false;
308 if (tm == TCP_METRICS_RECLAIM_PTR) { 324 if (tm == TCP_METRICS_RECLAIM_PTR) {
309 reclaim = true; 325 reclaim = true;
310 tm = NULL; 326 tm = NULL;
311 } 327 }
312 if (!tm && create) 328 if (!tm && create)
313 tm = tcpm_new(dst, &daddr, hash, reclaim); 329 tm = tcpm_new(dst, &saddr, &daddr, hash, reclaim);
314 else 330 else
315 tcpm_check_stamp(tm, dst); 331 tcpm_check_stamp(tm, dst);
316 332