aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/tcp_metrics.c151
1 files changed, 103 insertions, 48 deletions
diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c
index 06493736fbc8..699a42faab9c 100644
--- a/net/ipv4/tcp_metrics.c
+++ b/net/ipv4/tcp_metrics.c
@@ -31,7 +31,8 @@ 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_addr; 34 struct inetpeer_addr tcpm_saddr;
35 struct inetpeer_addr tcpm_daddr;
35 unsigned long tcpm_stamp; 36 unsigned long tcpm_stamp;
36 u32 tcpm_ts; 37 u32 tcpm_ts;
37 u32 tcpm_ts_stamp; 38 u32 tcpm_ts_stamp;
@@ -131,7 +132,8 @@ 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,
134 struct inetpeer_addr *addr, 135 struct inetpeer_addr *saddr,
136 struct inetpeer_addr *daddr,
135 unsigned int hash, 137 unsigned int hash,
136 bool reclaim) 138 bool reclaim)
137{ 139{
@@ -155,7 +157,8 @@ 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 }
158 tm->tcpm_addr = *addr; 160 tm->tcpm_saddr = *saddr;
161 tm->tcpm_daddr = *daddr;
159 162
160 tcpm_suck_dst(tm, dst, true); 163 tcpm_suck_dst(tm, dst, true);
161 164
@@ -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 *addr, 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 *a
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_addr, addr)) 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,19 +213,22 @@ 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 addr; 216 struct inetpeer_addr saddr, daddr;
212 unsigned int hash; 217 unsigned int hash;
213 struct net *net; 218 struct net *net;
214 219
215 addr.family = req->rsk_ops->family; 220 saddr.family = req->rsk_ops->family;
216 switch (addr.family) { 221 daddr.family = req->rsk_ops->family;
222 switch (daddr.family) {
217 case AF_INET: 223 case AF_INET:
218 addr.addr.a4 = inet_rsk(req)->ir_rmt_addr; 224 saddr.addr.a4 = inet_rsk(req)->ir_loc_addr;
219 hash = (__force unsigned int) addr.addr.a4; 225 daddr.addr.a4 = inet_rsk(req)->ir_rmt_addr;
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:
223 *(struct in6_addr *)addr.addr.a6 = inet_rsk(req)->ir_v6_rmt_addr; 230 *(struct in6_addr *)saddr.addr.a6 = inet_rsk(req)->ir_v6_loc_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;
226#endif 234#endif
@@ -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_addr, &addr)) 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,19 +252,22 @@ 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 addr; 255 struct inetpeer_addr saddr, daddr;
247 unsigned int hash; 256 unsigned int hash;
248 struct net *net; 257 struct net *net;
249 258
250 addr.family = tw->tw_family; 259 saddr.family = tw->tw_family;
251 switch (addr.family) { 260 daddr.family = tw->tw_family;
261 switch (daddr.family) {
252 case AF_INET: 262 case AF_INET:
253 addr.addr.a4 = tw->tw_daddr; 263 saddr.addr.a4 = tw->tw_rcv_saddr;
254 hash = (__force unsigned int) addr.addr.a4; 264 daddr.addr.a4 = tw->tw_daddr;
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:
258 *(struct in6_addr *)addr.addr.a6 = tw->tw_v6_daddr; 269 *(struct in6_addr *)saddr.addr.a6 = tw->tw_v6_rcv_saddr;
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;
261#endif 273#endif
@@ -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_addr, &addr)) 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,20 +292,23 @@ 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 addr; 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
287 addr.family = sk->sk_family; 300 saddr.family = sk->sk_family;
288 switch (addr.family) { 301 daddr.family = sk->sk_family;
302 switch (daddr.family) {
289 case AF_INET: 303 case AF_INET:
290 addr.addr.a4 = inet_sk(sk)->inet_daddr; 304 saddr.addr.a4 = inet_sk(sk)->inet_saddr;
291 hash = (__force unsigned int) addr.addr.a4; 305 daddr.addr.a4 = inet_sk(sk)->inet_daddr;
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:
295 *(struct in6_addr *)addr.addr.a6 = sk->sk_v6_daddr; 310 *(struct in6_addr *)saddr.addr.a6 = sk->sk_v6_rcv_saddr;
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;
298#endif 314#endif
@@ -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(&addr, 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, &addr, 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
@@ -724,15 +740,21 @@ static int tcp_metrics_fill_info(struct sk_buff *msg,
724 struct nlattr *nest; 740 struct nlattr *nest;
725 int i; 741 int i;
726 742
727 switch (tm->tcpm_addr.family) { 743 switch (tm->tcpm_daddr.family) {
728 case AF_INET: 744 case AF_INET:
729 if (nla_put_be32(msg, TCP_METRICS_ATTR_ADDR_IPV4, 745 if (nla_put_be32(msg, TCP_METRICS_ATTR_ADDR_IPV4,
730 tm->tcpm_addr.addr.a4) < 0) 746 tm->tcpm_daddr.addr.a4) < 0)
747 goto nla_put_failure;
748 if (nla_put_be32(msg, TCP_METRICS_ATTR_SADDR_IPV4,
749 tm->tcpm_saddr.addr.a4) < 0)
731 goto nla_put_failure; 750 goto nla_put_failure;
732 break; 751 break;
733 case AF_INET6: 752 case AF_INET6:
734 if (nla_put(msg, TCP_METRICS_ATTR_ADDR_IPV6, 16, 753 if (nla_put(msg, TCP_METRICS_ATTR_ADDR_IPV6, 16,
735 tm->tcpm_addr.addr.a6) < 0) 754 tm->tcpm_daddr.addr.a6) < 0)
755 goto nla_put_failure;
756 if (nla_put(msg, TCP_METRICS_ATTR_SADDR_IPV6, 16,
757 tm->tcpm_saddr.addr.a6) < 0)
736 goto nla_put_failure; 758 goto nla_put_failure;
737 break; 759 break;
738 default: 760 default:
@@ -855,44 +877,66 @@ done:
855 return skb->len; 877 return skb->len;
856} 878}
857 879
858static int parse_nl_addr(struct genl_info *info, struct inetpeer_addr *addr, 880static int __parse_nl_addr(struct genl_info *info, struct inetpeer_addr *addr,
859 unsigned int *hash, int optional) 881 unsigned int *hash, int optional, int v4, int v6)
860{ 882{
861 struct nlattr *a; 883 struct nlattr *a;
862 884
863 a = info->attrs[TCP_METRICS_ATTR_ADDR_IPV4]; 885 a = info->attrs[v4];
864 if (a) { 886 if (a) {
865 addr->family = AF_INET; 887 addr->family = AF_INET;
866 addr->addr.a4 = nla_get_be32(a); 888 addr->addr.a4 = nla_get_be32(a);
867 *hash = (__force unsigned int) addr->addr.a4; 889 if (hash)
890 *hash = (__force unsigned int) addr->addr.a4;
868 return 0; 891 return 0;
869 } 892 }
870 a = info->attrs[TCP_METRICS_ATTR_ADDR_IPV6]; 893 a = info->attrs[v6];
871 if (a) { 894 if (a) {
872 if (nla_len(a) != sizeof(struct in6_addr)) 895 if (nla_len(a) != sizeof(struct in6_addr))
873 return -EINVAL; 896 return -EINVAL;
874 addr->family = AF_INET6; 897 addr->family = AF_INET6;
875 memcpy(addr->addr.a6, nla_data(a), sizeof(addr->addr.a6)); 898 memcpy(addr->addr.a6, nla_data(a), sizeof(addr->addr.a6));
876 *hash = ipv6_addr_hash((struct in6_addr *) addr->addr.a6); 899 if (hash)
900 *hash = ipv6_addr_hash((struct in6_addr *) addr->addr.a6);
877 return 0; 901 return 0;
878 } 902 }
879 return optional ? 1 : -EAFNOSUPPORT; 903 return optional ? 1 : -EAFNOSUPPORT;
880} 904}
881 905
906static int parse_nl_addr(struct genl_info *info, struct inetpeer_addr *addr,
907 unsigned int *hash, int optional)
908{
909 return __parse_nl_addr(info, addr, hash, optional,
910 TCP_METRICS_ATTR_ADDR_IPV4,
911 TCP_METRICS_ATTR_ADDR_IPV6);
912}
913
914static int parse_nl_saddr(struct genl_info *info, struct inetpeer_addr *addr)
915{
916 return __parse_nl_addr(info, addr, NULL, 0,
917 TCP_METRICS_ATTR_SADDR_IPV4,
918 TCP_METRICS_ATTR_SADDR_IPV6);
919}
920
882static int tcp_metrics_nl_cmd_get(struct sk_buff *skb, struct genl_info *info) 921static int tcp_metrics_nl_cmd_get(struct sk_buff *skb, struct genl_info *info)
883{ 922{
884 struct tcp_metrics_block *tm; 923 struct tcp_metrics_block *tm;
885 struct inetpeer_addr addr; 924 struct inetpeer_addr saddr, daddr;
886 unsigned int hash; 925 unsigned int hash;
887 struct sk_buff *msg; 926 struct sk_buff *msg;
888 struct net *net = genl_info_net(info); 927 struct net *net = genl_info_net(info);
889 void *reply; 928 void *reply;
890 int ret; 929 int ret;
930 bool src = true;
891 931
892 ret = parse_nl_addr(info, &addr, &hash, 0); 932 ret = parse_nl_addr(info, &daddr, &hash, 0);
893 if (ret < 0) 933 if (ret < 0)
894 return ret; 934 return ret;
895 935
936 ret = parse_nl_saddr(info, &saddr);
937 if (ret < 0)
938 src = false;
939
896 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 940 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
897 if (!msg) 941 if (!msg)
898 return -ENOMEM; 942 return -ENOMEM;
@@ -907,7 +951,8 @@ static int tcp_metrics_nl_cmd_get(struct sk_buff *skb, struct genl_info *info)
907 rcu_read_lock(); 951 rcu_read_lock();
908 for (tm = rcu_dereference(net->ipv4.tcp_metrics_hash[hash].chain); tm; 952 for (tm = rcu_dereference(net->ipv4.tcp_metrics_hash[hash].chain); tm;
909 tm = rcu_dereference(tm->tcpm_next)) { 953 tm = rcu_dereference(tm->tcpm_next)) {
910 if (addr_same(&tm->tcpm_addr, &addr)) { 954 if (addr_same(&tm->tcpm_daddr, &daddr) &&
955 (!src || addr_same(&tm->tcpm_saddr, &saddr))) {
911 ret = tcp_metrics_fill_info(msg, tm); 956 ret = tcp_metrics_fill_info(msg, tm);
912 break; 957 break;
913 } 958 }
@@ -960,34 +1005,44 @@ static int tcp_metrics_flush_all(struct net *net)
960static int tcp_metrics_nl_cmd_del(struct sk_buff *skb, struct genl_info *info) 1005static int tcp_metrics_nl_cmd_del(struct sk_buff *skb, struct genl_info *info)
961{ 1006{
962 struct tcpm_hash_bucket *hb; 1007 struct tcpm_hash_bucket *hb;
963 struct tcp_metrics_block *tm; 1008 struct tcp_metrics_block *tm, *tmlist = NULL;
964 struct tcp_metrics_block __rcu **pp; 1009 struct tcp_metrics_block __rcu **pp;
965 struct inetpeer_addr addr; 1010 struct inetpeer_addr saddr, daddr;
966 unsigned int hash; 1011 unsigned int hash;
967 struct net *net = genl_info_net(info); 1012 struct net *net = genl_info_net(info);
968 int ret; 1013 int ret;
1014 bool src = true;
969 1015
970 ret = parse_nl_addr(info, &addr, &hash, 1); 1016 ret = parse_nl_addr(info, &daddr, &hash, 1);
971 if (ret < 0) 1017 if (ret < 0)
972 return ret; 1018 return ret;
973 if (ret > 0) 1019 if (ret > 0)
974 return tcp_metrics_flush_all(net); 1020 return tcp_metrics_flush_all(net);
1021 ret = parse_nl_saddr(info, &saddr);
1022 if (ret < 0)
1023 src = false;
975 1024
976 hash = hash_32(hash, net->ipv4.tcp_metrics_hash_log); 1025 hash = hash_32(hash, net->ipv4.tcp_metrics_hash_log);
977 hb = net->ipv4.tcp_metrics_hash + hash; 1026 hb = net->ipv4.tcp_metrics_hash + hash;
978 pp = &hb->chain; 1027 pp = &hb->chain;
979 spin_lock_bh(&tcp_metrics_lock); 1028 spin_lock_bh(&tcp_metrics_lock);
980 for (tm = deref_locked_genl(*pp); tm; 1029 for (tm = deref_locked_genl(*pp); tm; tm = deref_locked_genl(*pp)) {
981 pp = &tm->tcpm_next, tm = deref_locked_genl(*pp)) { 1030 if (addr_same(&tm->tcpm_daddr, &daddr) &&
982 if (addr_same(&tm->tcpm_addr, &addr)) { 1031 (!src || addr_same(&tm->tcpm_saddr, &saddr))) {
983 *pp = tm->tcpm_next; 1032 *pp = tm->tcpm_next;
984 break; 1033 tm->tcpm_next = tmlist;
1034 tmlist = tm;
1035 } else {
1036 pp = &tm->tcpm_next;
985 } 1037 }
986 } 1038 }
987 spin_unlock_bh(&tcp_metrics_lock); 1039 spin_unlock_bh(&tcp_metrics_lock);
988 if (!tm) 1040 if (!tmlist)
989 return -ESRCH; 1041 return -ESRCH;
990 kfree_rcu(tm, rcu_head); 1042 for (tm = tmlist; tm; tm = tmlist) {
1043 tmlist = tm->tcpm_next;
1044 kfree_rcu(tm, rcu_head);
1045 }
991 return 0; 1046 return 0;
992} 1047}
993 1048