Blame view

net/rds/bind.c 5.2 KB
639b321b4   Andy Grover   RDS: Socket inter...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
  /*
   * Copyright (c) 2006 Oracle.  All rights reserved.
   *
   * This software is available to you under a choice of one of two
   * licenses.  You may choose to be licensed under the terms of the GNU
   * General Public License (GPL) Version 2, available from the file
   * COPYING in the main directory of this source tree, or the
   * OpenIB.org BSD license below:
   *
   *     Redistribution and use in source and binary forms, with or
   *     without modification, are permitted provided that the following
   *     conditions are met:
   *
   *      - Redistributions of source code must retain the above
   *        copyright notice, this list of conditions and the following
   *        disclaimer.
   *
   *      - Redistributions in binary form must reproduce the above
   *        copyright notice, this list of conditions and the following
   *        disclaimer in the documentation and/or other materials
   *        provided with the distribution.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
   * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
   * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
   * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   * SOFTWARE.
   *
   */
  #include <linux/kernel.h>
  #include <net/sock.h>
  #include <linux/in.h>
  #include <linux/if_arp.h>
38a4e5e61   Chris Mason   rds: Use RCU for ...
37
  #include <linux/jhash.h>
cb0a60564   Manuel Zerpies   net/rds: use prin...
38
  #include <linux/ratelimit.h>
639b321b4   Andy Grover   RDS: Socket inter...
39
  #include "rds.h"
7b5654349   santosh.shilimkar@oracle.com   RDS: convert bind...
40
  static struct rhashtable bind_hash_table;
8209432a5   Bhumika Goyal   RDS: make rhashta...
41
  static const struct rhashtable_params ht_parms = {
7b5654349   santosh.shilimkar@oracle.com   RDS: convert bind...
42
43
44
45
46
47
  	.nelem_hint = 768,
  	.key_len = sizeof(u64),
  	.key_offset = offsetof(struct rds_sock, rs_bound_key),
  	.head_offset = offsetof(struct rds_sock, rs_bound_node),
  	.max_size = 16384,
  	.min_size = 1024,
9b9acde7e   Santosh Shilimkar   RDS: Use per-buck...
48
  };
639b321b4   Andy Grover   RDS: Socket inter...
49
50
51
52
53
54
55
56
  /*
   * Return the rds_sock bound at the given local address.
   *
   * The rx path can race with rds_release.  We notice if rds_release() has
   * marked this socket and don't return a rs ref to the rx path.
   */
  struct rds_sock *rds_find_bound(__be32 addr, __be16 port)
  {
7b5654349   santosh.shilimkar@oracle.com   RDS: convert bind...
57
  	u64 key = ((u64)addr << 32) | port;
639b321b4   Andy Grover   RDS: Socket inter...
58
  	struct rds_sock *rs;
38a4e5e61   Chris Mason   rds: Use RCU for ...
59

5ff9c51cb   Cong Wang   rds: fix two RCU ...
60
61
  	rcu_read_lock();
  	rs = rhashtable_lookup(&bind_hash_table, &key, ht_parms);
7b5654349   santosh.shilimkar@oracle.com   RDS: convert bind...
62
63
64
  	if (rs && !sock_flag(rds_rs_to_sk(rs), SOCK_DEAD))
  		rds_sock_addref(rs);
  	else
639b321b4   Andy Grover   RDS: Socket inter...
65
  		rs = NULL;
5ff9c51cb   Cong Wang   rds: fix two RCU ...
66
  	rcu_read_unlock();
639b321b4   Andy Grover   RDS: Socket inter...
67
68
69
70
  
  	rdsdebug("returning rs %p for %pI4:%u
  ", rs, &addr,
  		ntohs(port));
8b0a6b461   Santosh Shilimkar   RDS: make socket ...
71

639b321b4   Andy Grover   RDS: Socket inter...
72
73
74
75
76
77
  	return rs;
  }
  
  /* returns -ve errno or +ve port */
  static int rds_add_bound(struct rds_sock *rs, __be32 addr, __be16 *port)
  {
639b321b4   Andy Grover   RDS: Socket inter...
78
79
  	int ret = -EADDRINUSE;
  	u16 rover, last;
7b5654349   santosh.shilimkar@oracle.com   RDS: convert bind...
80
  	u64 key;
639b321b4   Andy Grover   RDS: Socket inter...
81
82
83
  
  	if (*port != 0) {
  		rover = be16_to_cpu(*port);
5916e2c15   Sowmini Varadhan   RDS: TCP: Enable ...
84
85
  		if (rover == RDS_FLAG_PROBE_PORT)
  			return -EINVAL;
639b321b4   Andy Grover   RDS: Socket inter...
86
87
  		last = rover;
  	} else {
63862b5be   Aruna-Hewapathirane   net: replace macr...
88
  		rover = max_t(u16, prandom_u32(), 2);
639b321b4   Andy Grover   RDS: Socket inter...
89
90
  		last = rover - 1;
  	}
639b321b4   Andy Grover   RDS: Socket inter...
91
92
93
  	do {
  		if (rover == 0)
  			rover++;
9b9acde7e   Santosh Shilimkar   RDS: Use per-buck...
94

5916e2c15   Sowmini Varadhan   RDS: TCP: Enable ...
95
96
  		if (rover == RDS_FLAG_PROBE_PORT)
  			continue;
7b5654349   santosh.shilimkar@oracle.com   RDS: convert bind...
97
98
99
100
101
102
  		key = ((u64)addr << 32) | cpu_to_be16(rover);
  		if (rhashtable_lookup_fast(&bind_hash_table, &key, ht_parms))
  			continue;
  
  		rs->rs_bound_key = key;
  		rs->rs_bound_addr = addr;
5916e2c15   Sowmini Varadhan   RDS: TCP: Enable ...
103
104
  		net_get_random_once(&rs->rs_hash_initval,
  				    sizeof(rs->rs_hash_initval));
7b5654349   santosh.shilimkar@oracle.com   RDS: convert bind...
105
106
107
108
109
  		rs->rs_bound_port = cpu_to_be16(rover);
  		rs->rs_bound_node.next = NULL;
  		rds_sock_addref(rs);
  		if (!rhashtable_insert_fast(&bind_hash_table,
  					    &rs->rs_bound_node, ht_parms)) {
38a4e5e61   Chris Mason   rds: Use RCU for ...
110
  			*port = rs->rs_bound_port;
639b321b4   Andy Grover   RDS: Socket inter...
111
  			ret = 0;
38a4e5e61   Chris Mason   rds: Use RCU for ...
112
113
114
  			rdsdebug("rs %p binding to %pI4:%d
  ",
  			  rs, &addr, (int)ntohs(*port));
639b321b4   Andy Grover   RDS: Socket inter...
115
  			break;
281269598   Santosh Shilimkar   RDS: fix rds_sock...
116
  		} else {
ea620e414   Sowmini Varadhan   rds; Reset rs->rs...
117
  			rs->rs_bound_addr = 0;
7b5654349   santosh.shilimkar@oracle.com   RDS: convert bind...
118
119
120
  			rds_sock_put(rs);
  			ret = -ENOMEM;
  			break;
639b321b4   Andy Grover   RDS: Socket inter...
121
122
  		}
  	} while (rover++ != last);
639b321b4   Andy Grover   RDS: Socket inter...
123
124
125
126
127
  	return ret;
  }
  
  void rds_remove_bound(struct rds_sock *rs)
  {
639b321b4   Andy Grover   RDS: Socket inter...
128

7b5654349   santosh.shilimkar@oracle.com   RDS: convert bind...
129
130
  	if (!rs->rs_bound_addr)
  		return;
639b321b4   Andy Grover   RDS: Socket inter...
131

7b5654349   santosh.shilimkar@oracle.com   RDS: convert bind...
132
133
134
135
  	rdsdebug("rs %p unbinding from %pI4:%d
  ",
  		 rs, &rs->rs_bound_addr,
  		 ntohs(rs->rs_bound_port));
639b321b4   Andy Grover   RDS: Socket inter...
136

7b5654349   santosh.shilimkar@oracle.com   RDS: convert bind...
137
138
139
  	rhashtable_remove_fast(&bind_hash_table, &rs->rs_bound_node, ht_parms);
  	rds_sock_put(rs);
  	rs->rs_bound_addr = 0;
639b321b4   Andy Grover   RDS: Socket inter...
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
  }
  
  int rds_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
  {
  	struct sock *sk = sock->sk;
  	struct sockaddr_in *sin = (struct sockaddr_in *)uaddr;
  	struct rds_sock *rs = rds_sk_to_rs(sk);
  	struct rds_transport *trans;
  	int ret = 0;
  
  	lock_sock(sk);
  
  	if (addr_len != sizeof(struct sockaddr_in) ||
  	    sin->sin_family != AF_INET ||
  	    rs->rs_bound_addr ||
  	    sin->sin_addr.s_addr == htonl(INADDR_ANY)) {
  		ret = -EINVAL;
  		goto out;
  	}
5ff9c51cb   Cong Wang   rds: fix two RCU ...
159
  	sock_set_flag(sk, SOCK_RCU_FREE);
639b321b4   Andy Grover   RDS: Socket inter...
160
161
162
  	ret = rds_add_bound(rs, sin->sin_addr.s_addr, &sin->sin_port);
  	if (ret)
  		goto out;
d97dac54b   Sowmini Varadhan   net/rds: Add sets...
163
  	if (rs->rs_transport) { /* previously bound */
486798001   Sowmini Varadhan   RDS: Invoke ->lad...
164
165
166
167
168
169
170
171
  		trans = rs->rs_transport;
  		if (trans->laddr_check(sock_net(sock->sk),
  				       sin->sin_addr.s_addr) != 0) {
  			ret = -ENOPROTOOPT;
  			rds_remove_bound(rs);
  		} else {
  			ret = 0;
  		}
d97dac54b   Sowmini Varadhan   net/rds: Add sets...
172
173
  		goto out;
  	}
d5a8ac28a   Sowmini Varadhan   RDS-TCP: Make RDS...
174
175
  	trans = rds_trans_get_preferred(sock_net(sock->sk),
  					sin->sin_addr.s_addr);
8690bfa17   Andy Grover   RDS: cleanup: rem...
176
  	if (!trans) {
639b321b4   Andy Grover   RDS: Socket inter...
177
178
  		ret = -EADDRNOTAVAIL;
  		rds_remove_bound(rs);
f69b22e65   Santosh Shilimkar   RDS: log the addr...
179
180
181
  		pr_info_ratelimited("RDS: %s could not find a transport for %pI4, load rds_tcp or rds_rdma?
  ",
  				    __func__, &sin->sin_addr.s_addr);
639b321b4   Andy Grover   RDS: Socket inter...
182
183
184
185
186
187
188
189
190
191
  		goto out;
  	}
  
  	rs->rs_transport = trans;
  	ret = 0;
  
  out:
  	release_sock(sk);
  	return ret;
  }
9b9acde7e   Santosh Shilimkar   RDS: Use per-buck...
192

7b5654349   santosh.shilimkar@oracle.com   RDS: convert bind...
193
  void rds_bind_lock_destroy(void)
9b9acde7e   Santosh Shilimkar   RDS: Use per-buck...
194
  {
7b5654349   santosh.shilimkar@oracle.com   RDS: convert bind...
195
196
  	rhashtable_destroy(&bind_hash_table);
  }
9b9acde7e   Santosh Shilimkar   RDS: Use per-buck...
197

7b5654349   santosh.shilimkar@oracle.com   RDS: convert bind...
198
199
200
  int rds_bind_lock_init(void)
  {
  	return rhashtable_init(&bind_hash_table, &ht_parms);
9b9acde7e   Santosh Shilimkar   RDS: Use per-buck...
201
  }