162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * This software is available to you under a choice of one of two 562306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 662306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 762306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 862306a36Sopenharmony_ci * OpenIB.org BSD license below: 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1162306a36Sopenharmony_ci * without modification, are permitted provided that the following 1262306a36Sopenharmony_ci * conditions are met: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1562306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1662306a36Sopenharmony_ci * disclaimer. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 1962306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2062306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2162306a36Sopenharmony_ci * provided with the distribution. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2462306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2562306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2662306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2762306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 2862306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 2962306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3062306a36Sopenharmony_ci * SOFTWARE. 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci */ 3362306a36Sopenharmony_ci#include <linux/kernel.h> 3462306a36Sopenharmony_ci#include <linux/list.h> 3562306a36Sopenharmony_ci#include <linux/slab.h> 3662306a36Sopenharmony_ci#include <linux/export.h> 3762306a36Sopenharmony_ci#include <net/ipv6.h> 3862306a36Sopenharmony_ci#include <net/inet6_hashtables.h> 3962306a36Sopenharmony_ci#include <net/addrconf.h> 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#include "rds.h" 4262306a36Sopenharmony_ci#include "loop.h" 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#define RDS_CONNECTION_HASH_BITS 12 4562306a36Sopenharmony_ci#define RDS_CONNECTION_HASH_ENTRIES (1 << RDS_CONNECTION_HASH_BITS) 4662306a36Sopenharmony_ci#define RDS_CONNECTION_HASH_MASK (RDS_CONNECTION_HASH_ENTRIES - 1) 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/* converting this to RCU is a chore for another day.. */ 4962306a36Sopenharmony_cistatic DEFINE_SPINLOCK(rds_conn_lock); 5062306a36Sopenharmony_cistatic unsigned long rds_conn_count; 5162306a36Sopenharmony_cistatic struct hlist_head rds_conn_hash[RDS_CONNECTION_HASH_ENTRIES]; 5262306a36Sopenharmony_cistatic struct kmem_cache *rds_conn_slab; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic struct hlist_head *rds_conn_bucket(const struct in6_addr *laddr, 5562306a36Sopenharmony_ci const struct in6_addr *faddr) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci static u32 rds6_hash_secret __read_mostly; 5862306a36Sopenharmony_ci static u32 rds_hash_secret __read_mostly; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci u32 lhash, fhash, hash; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci net_get_random_once(&rds_hash_secret, sizeof(rds_hash_secret)); 6362306a36Sopenharmony_ci net_get_random_once(&rds6_hash_secret, sizeof(rds6_hash_secret)); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci lhash = (__force u32)laddr->s6_addr32[3]; 6662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 6762306a36Sopenharmony_ci fhash = __ipv6_addr_jhash(faddr, rds6_hash_secret); 6862306a36Sopenharmony_ci#else 6962306a36Sopenharmony_ci fhash = (__force u32)faddr->s6_addr32[3]; 7062306a36Sopenharmony_ci#endif 7162306a36Sopenharmony_ci hash = __inet_ehashfn(lhash, 0, fhash, 0, rds_hash_secret); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci return &rds_conn_hash[hash & RDS_CONNECTION_HASH_MASK]; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci#define rds_conn_info_set(var, test, suffix) do { \ 7762306a36Sopenharmony_ci if (test) \ 7862306a36Sopenharmony_ci var |= RDS_INFO_CONNECTION_FLAG_##suffix; \ 7962306a36Sopenharmony_ci} while (0) 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/* rcu read lock must be held or the connection spinlock */ 8262306a36Sopenharmony_cistatic struct rds_connection *rds_conn_lookup(struct net *net, 8362306a36Sopenharmony_ci struct hlist_head *head, 8462306a36Sopenharmony_ci const struct in6_addr *laddr, 8562306a36Sopenharmony_ci const struct in6_addr *faddr, 8662306a36Sopenharmony_ci struct rds_transport *trans, 8762306a36Sopenharmony_ci u8 tos, int dev_if) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci struct rds_connection *conn, *ret = NULL; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci hlist_for_each_entry_rcu(conn, head, c_hash_node) { 9262306a36Sopenharmony_ci if (ipv6_addr_equal(&conn->c_faddr, faddr) && 9362306a36Sopenharmony_ci ipv6_addr_equal(&conn->c_laddr, laddr) && 9462306a36Sopenharmony_ci conn->c_trans == trans && 9562306a36Sopenharmony_ci conn->c_tos == tos && 9662306a36Sopenharmony_ci net == rds_conn_net(conn) && 9762306a36Sopenharmony_ci conn->c_dev_if == dev_if) { 9862306a36Sopenharmony_ci ret = conn; 9962306a36Sopenharmony_ci break; 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci rdsdebug("returning conn %p for %pI6c -> %pI6c\n", ret, 10362306a36Sopenharmony_ci laddr, faddr); 10462306a36Sopenharmony_ci return ret; 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci/* 10862306a36Sopenharmony_ci * This is called by transports as they're bringing down a connection. 10962306a36Sopenharmony_ci * It clears partial message state so that the transport can start sending 11062306a36Sopenharmony_ci * and receiving over this connection again in the future. It is up to 11162306a36Sopenharmony_ci * the transport to have serialized this call with its send and recv. 11262306a36Sopenharmony_ci */ 11362306a36Sopenharmony_cistatic void rds_conn_path_reset(struct rds_conn_path *cp) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci struct rds_connection *conn = cp->cp_conn; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci rdsdebug("connection %pI6c to %pI6c reset\n", 11862306a36Sopenharmony_ci &conn->c_laddr, &conn->c_faddr); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci rds_stats_inc(s_conn_reset); 12162306a36Sopenharmony_ci rds_send_path_reset(cp); 12262306a36Sopenharmony_ci cp->cp_flags = 0; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci /* Do not clear next_rx_seq here, else we cannot distinguish 12562306a36Sopenharmony_ci * retransmitted packets from new packets, and will hand all 12662306a36Sopenharmony_ci * of them to the application. That is not consistent with the 12762306a36Sopenharmony_ci * reliability guarantees of RDS. */ 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic void __rds_conn_path_init(struct rds_connection *conn, 13162306a36Sopenharmony_ci struct rds_conn_path *cp, bool is_outgoing) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci spin_lock_init(&cp->cp_lock); 13462306a36Sopenharmony_ci cp->cp_next_tx_seq = 1; 13562306a36Sopenharmony_ci init_waitqueue_head(&cp->cp_waitq); 13662306a36Sopenharmony_ci INIT_LIST_HEAD(&cp->cp_send_queue); 13762306a36Sopenharmony_ci INIT_LIST_HEAD(&cp->cp_retrans); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci cp->cp_conn = conn; 14062306a36Sopenharmony_ci atomic_set(&cp->cp_state, RDS_CONN_DOWN); 14162306a36Sopenharmony_ci cp->cp_send_gen = 0; 14262306a36Sopenharmony_ci cp->cp_reconnect_jiffies = 0; 14362306a36Sopenharmony_ci cp->cp_conn->c_proposed_version = RDS_PROTOCOL_VERSION; 14462306a36Sopenharmony_ci INIT_DELAYED_WORK(&cp->cp_send_w, rds_send_worker); 14562306a36Sopenharmony_ci INIT_DELAYED_WORK(&cp->cp_recv_w, rds_recv_worker); 14662306a36Sopenharmony_ci INIT_DELAYED_WORK(&cp->cp_conn_w, rds_connect_worker); 14762306a36Sopenharmony_ci INIT_WORK(&cp->cp_down_w, rds_shutdown_worker); 14862306a36Sopenharmony_ci mutex_init(&cp->cp_cm_lock); 14962306a36Sopenharmony_ci cp->cp_flags = 0; 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci/* 15362306a36Sopenharmony_ci * There is only every one 'conn' for a given pair of addresses in the 15462306a36Sopenharmony_ci * system at a time. They contain messages to be retransmitted and so 15562306a36Sopenharmony_ci * span the lifetime of the actual underlying transport connections. 15662306a36Sopenharmony_ci * 15762306a36Sopenharmony_ci * For now they are not garbage collected once they're created. They 15862306a36Sopenharmony_ci * are torn down as the module is removed, if ever. 15962306a36Sopenharmony_ci */ 16062306a36Sopenharmony_cistatic struct rds_connection *__rds_conn_create(struct net *net, 16162306a36Sopenharmony_ci const struct in6_addr *laddr, 16262306a36Sopenharmony_ci const struct in6_addr *faddr, 16362306a36Sopenharmony_ci struct rds_transport *trans, 16462306a36Sopenharmony_ci gfp_t gfp, u8 tos, 16562306a36Sopenharmony_ci int is_outgoing, 16662306a36Sopenharmony_ci int dev_if) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci struct rds_connection *conn, *parent = NULL; 16962306a36Sopenharmony_ci struct hlist_head *head = rds_conn_bucket(laddr, faddr); 17062306a36Sopenharmony_ci struct rds_transport *loop_trans; 17162306a36Sopenharmony_ci unsigned long flags; 17262306a36Sopenharmony_ci int ret, i; 17362306a36Sopenharmony_ci int npaths = (trans->t_mp_capable ? RDS_MPATH_WORKERS : 1); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci rcu_read_lock(); 17662306a36Sopenharmony_ci conn = rds_conn_lookup(net, head, laddr, faddr, trans, tos, dev_if); 17762306a36Sopenharmony_ci if (conn && 17862306a36Sopenharmony_ci conn->c_loopback && 17962306a36Sopenharmony_ci conn->c_trans != &rds_loop_transport && 18062306a36Sopenharmony_ci ipv6_addr_equal(laddr, faddr) && 18162306a36Sopenharmony_ci !is_outgoing) { 18262306a36Sopenharmony_ci /* This is a looped back IB connection, and we're 18362306a36Sopenharmony_ci * called by the code handling the incoming connect. 18462306a36Sopenharmony_ci * We need a second connection object into which we 18562306a36Sopenharmony_ci * can stick the other QP. */ 18662306a36Sopenharmony_ci parent = conn; 18762306a36Sopenharmony_ci conn = parent->c_passive; 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci rcu_read_unlock(); 19062306a36Sopenharmony_ci if (conn) 19162306a36Sopenharmony_ci goto out; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci conn = kmem_cache_zalloc(rds_conn_slab, gfp); 19462306a36Sopenharmony_ci if (!conn) { 19562306a36Sopenharmony_ci conn = ERR_PTR(-ENOMEM); 19662306a36Sopenharmony_ci goto out; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci conn->c_path = kcalloc(npaths, sizeof(struct rds_conn_path), gfp); 19962306a36Sopenharmony_ci if (!conn->c_path) { 20062306a36Sopenharmony_ci kmem_cache_free(rds_conn_slab, conn); 20162306a36Sopenharmony_ci conn = ERR_PTR(-ENOMEM); 20262306a36Sopenharmony_ci goto out; 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci INIT_HLIST_NODE(&conn->c_hash_node); 20662306a36Sopenharmony_ci conn->c_laddr = *laddr; 20762306a36Sopenharmony_ci conn->c_isv6 = !ipv6_addr_v4mapped(laddr); 20862306a36Sopenharmony_ci conn->c_faddr = *faddr; 20962306a36Sopenharmony_ci conn->c_dev_if = dev_if; 21062306a36Sopenharmony_ci conn->c_tos = tos; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 21362306a36Sopenharmony_ci /* If the local address is link local, set c_bound_if to be the 21462306a36Sopenharmony_ci * index used for this connection. Otherwise, set it to 0 as 21562306a36Sopenharmony_ci * the socket is not bound to an interface. c_bound_if is used 21662306a36Sopenharmony_ci * to look up a socket when a packet is received 21762306a36Sopenharmony_ci */ 21862306a36Sopenharmony_ci if (ipv6_addr_type(laddr) & IPV6_ADDR_LINKLOCAL) 21962306a36Sopenharmony_ci conn->c_bound_if = dev_if; 22062306a36Sopenharmony_ci else 22162306a36Sopenharmony_ci#endif 22262306a36Sopenharmony_ci conn->c_bound_if = 0; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci rds_conn_net_set(conn, net); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci ret = rds_cong_get_maps(conn); 22762306a36Sopenharmony_ci if (ret) { 22862306a36Sopenharmony_ci kfree(conn->c_path); 22962306a36Sopenharmony_ci kmem_cache_free(rds_conn_slab, conn); 23062306a36Sopenharmony_ci conn = ERR_PTR(ret); 23162306a36Sopenharmony_ci goto out; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci /* 23562306a36Sopenharmony_ci * This is where a connection becomes loopback. If *any* RDS sockets 23662306a36Sopenharmony_ci * can bind to the destination address then we'd rather the messages 23762306a36Sopenharmony_ci * flow through loopback rather than either transport. 23862306a36Sopenharmony_ci */ 23962306a36Sopenharmony_ci loop_trans = rds_trans_get_preferred(net, faddr, conn->c_dev_if); 24062306a36Sopenharmony_ci if (loop_trans) { 24162306a36Sopenharmony_ci rds_trans_put(loop_trans); 24262306a36Sopenharmony_ci conn->c_loopback = 1; 24362306a36Sopenharmony_ci if (trans->t_prefer_loopback) { 24462306a36Sopenharmony_ci if (likely(is_outgoing)) { 24562306a36Sopenharmony_ci /* "outgoing" connection to local address. 24662306a36Sopenharmony_ci * Protocol says it wants the connection 24762306a36Sopenharmony_ci * handled by the loopback transport. 24862306a36Sopenharmony_ci * This is what TCP does. 24962306a36Sopenharmony_ci */ 25062306a36Sopenharmony_ci trans = &rds_loop_transport; 25162306a36Sopenharmony_ci } else { 25262306a36Sopenharmony_ci /* No transport currently in use 25362306a36Sopenharmony_ci * should end up here, but if it 25462306a36Sopenharmony_ci * does, reset/destroy the connection. 25562306a36Sopenharmony_ci */ 25662306a36Sopenharmony_ci kfree(conn->c_path); 25762306a36Sopenharmony_ci kmem_cache_free(rds_conn_slab, conn); 25862306a36Sopenharmony_ci conn = ERR_PTR(-EOPNOTSUPP); 25962306a36Sopenharmony_ci goto out; 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci conn->c_trans = trans; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci init_waitqueue_head(&conn->c_hs_waitq); 26762306a36Sopenharmony_ci for (i = 0; i < npaths; i++) { 26862306a36Sopenharmony_ci __rds_conn_path_init(conn, &conn->c_path[i], 26962306a36Sopenharmony_ci is_outgoing); 27062306a36Sopenharmony_ci conn->c_path[i].cp_index = i; 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci rcu_read_lock(); 27362306a36Sopenharmony_ci if (rds_destroy_pending(conn)) 27462306a36Sopenharmony_ci ret = -ENETDOWN; 27562306a36Sopenharmony_ci else 27662306a36Sopenharmony_ci ret = trans->conn_alloc(conn, GFP_ATOMIC); 27762306a36Sopenharmony_ci if (ret) { 27862306a36Sopenharmony_ci rcu_read_unlock(); 27962306a36Sopenharmony_ci kfree(conn->c_path); 28062306a36Sopenharmony_ci kmem_cache_free(rds_conn_slab, conn); 28162306a36Sopenharmony_ci conn = ERR_PTR(ret); 28262306a36Sopenharmony_ci goto out; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci rdsdebug("allocated conn %p for %pI6c -> %pI6c over %s %s\n", 28662306a36Sopenharmony_ci conn, laddr, faddr, 28762306a36Sopenharmony_ci strnlen(trans->t_name, sizeof(trans->t_name)) ? 28862306a36Sopenharmony_ci trans->t_name : "[unknown]", is_outgoing ? "(outgoing)" : ""); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci /* 29162306a36Sopenharmony_ci * Since we ran without holding the conn lock, someone could 29262306a36Sopenharmony_ci * have created the same conn (either normal or passive) in the 29362306a36Sopenharmony_ci * interim. We check while holding the lock. If we won, we complete 29462306a36Sopenharmony_ci * init and return our conn. If we lost, we rollback and return the 29562306a36Sopenharmony_ci * other one. 29662306a36Sopenharmony_ci */ 29762306a36Sopenharmony_ci spin_lock_irqsave(&rds_conn_lock, flags); 29862306a36Sopenharmony_ci if (parent) { 29962306a36Sopenharmony_ci /* Creating passive conn */ 30062306a36Sopenharmony_ci if (parent->c_passive) { 30162306a36Sopenharmony_ci trans->conn_free(conn->c_path[0].cp_transport_data); 30262306a36Sopenharmony_ci kfree(conn->c_path); 30362306a36Sopenharmony_ci kmem_cache_free(rds_conn_slab, conn); 30462306a36Sopenharmony_ci conn = parent->c_passive; 30562306a36Sopenharmony_ci } else { 30662306a36Sopenharmony_ci parent->c_passive = conn; 30762306a36Sopenharmony_ci rds_cong_add_conn(conn); 30862306a36Sopenharmony_ci rds_conn_count++; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci } else { 31162306a36Sopenharmony_ci /* Creating normal conn */ 31262306a36Sopenharmony_ci struct rds_connection *found; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci found = rds_conn_lookup(net, head, laddr, faddr, trans, 31562306a36Sopenharmony_ci tos, dev_if); 31662306a36Sopenharmony_ci if (found) { 31762306a36Sopenharmony_ci struct rds_conn_path *cp; 31862306a36Sopenharmony_ci int i; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci for (i = 0; i < npaths; i++) { 32162306a36Sopenharmony_ci cp = &conn->c_path[i]; 32262306a36Sopenharmony_ci /* The ->conn_alloc invocation may have 32362306a36Sopenharmony_ci * allocated resource for all paths, so all 32462306a36Sopenharmony_ci * of them may have to be freed here. 32562306a36Sopenharmony_ci */ 32662306a36Sopenharmony_ci if (cp->cp_transport_data) 32762306a36Sopenharmony_ci trans->conn_free(cp->cp_transport_data); 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci kfree(conn->c_path); 33062306a36Sopenharmony_ci kmem_cache_free(rds_conn_slab, conn); 33162306a36Sopenharmony_ci conn = found; 33262306a36Sopenharmony_ci } else { 33362306a36Sopenharmony_ci conn->c_my_gen_num = rds_gen_num; 33462306a36Sopenharmony_ci conn->c_peer_gen_num = 0; 33562306a36Sopenharmony_ci hlist_add_head_rcu(&conn->c_hash_node, head); 33662306a36Sopenharmony_ci rds_cong_add_conn(conn); 33762306a36Sopenharmony_ci rds_conn_count++; 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci spin_unlock_irqrestore(&rds_conn_lock, flags); 34162306a36Sopenharmony_ci rcu_read_unlock(); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ciout: 34462306a36Sopenharmony_ci return conn; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistruct rds_connection *rds_conn_create(struct net *net, 34862306a36Sopenharmony_ci const struct in6_addr *laddr, 34962306a36Sopenharmony_ci const struct in6_addr *faddr, 35062306a36Sopenharmony_ci struct rds_transport *trans, u8 tos, 35162306a36Sopenharmony_ci gfp_t gfp, int dev_if) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci return __rds_conn_create(net, laddr, faddr, trans, gfp, tos, 0, dev_if); 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rds_conn_create); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cistruct rds_connection *rds_conn_create_outgoing(struct net *net, 35862306a36Sopenharmony_ci const struct in6_addr *laddr, 35962306a36Sopenharmony_ci const struct in6_addr *faddr, 36062306a36Sopenharmony_ci struct rds_transport *trans, 36162306a36Sopenharmony_ci u8 tos, gfp_t gfp, int dev_if) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci return __rds_conn_create(net, laddr, faddr, trans, gfp, tos, 1, dev_if); 36462306a36Sopenharmony_ci} 36562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rds_conn_create_outgoing); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_civoid rds_conn_shutdown(struct rds_conn_path *cp) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci struct rds_connection *conn = cp->cp_conn; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci /* shut it down unless it's down already */ 37262306a36Sopenharmony_ci if (!rds_conn_path_transition(cp, RDS_CONN_DOWN, RDS_CONN_DOWN)) { 37362306a36Sopenharmony_ci /* 37462306a36Sopenharmony_ci * Quiesce the connection mgmt handlers before we start tearing 37562306a36Sopenharmony_ci * things down. We don't hold the mutex for the entire 37662306a36Sopenharmony_ci * duration of the shutdown operation, else we may be 37762306a36Sopenharmony_ci * deadlocking with the CM handler. Instead, the CM event 37862306a36Sopenharmony_ci * handler is supposed to check for state DISCONNECTING 37962306a36Sopenharmony_ci */ 38062306a36Sopenharmony_ci mutex_lock(&cp->cp_cm_lock); 38162306a36Sopenharmony_ci if (!rds_conn_path_transition(cp, RDS_CONN_UP, 38262306a36Sopenharmony_ci RDS_CONN_DISCONNECTING) && 38362306a36Sopenharmony_ci !rds_conn_path_transition(cp, RDS_CONN_ERROR, 38462306a36Sopenharmony_ci RDS_CONN_DISCONNECTING)) { 38562306a36Sopenharmony_ci rds_conn_path_error(cp, 38662306a36Sopenharmony_ci "shutdown called in state %d\n", 38762306a36Sopenharmony_ci atomic_read(&cp->cp_state)); 38862306a36Sopenharmony_ci mutex_unlock(&cp->cp_cm_lock); 38962306a36Sopenharmony_ci return; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci mutex_unlock(&cp->cp_cm_lock); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci wait_event(cp->cp_waitq, 39462306a36Sopenharmony_ci !test_bit(RDS_IN_XMIT, &cp->cp_flags)); 39562306a36Sopenharmony_ci wait_event(cp->cp_waitq, 39662306a36Sopenharmony_ci !test_bit(RDS_RECV_REFILL, &cp->cp_flags)); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci conn->c_trans->conn_path_shutdown(cp); 39962306a36Sopenharmony_ci rds_conn_path_reset(cp); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci if (!rds_conn_path_transition(cp, RDS_CONN_DISCONNECTING, 40262306a36Sopenharmony_ci RDS_CONN_DOWN) && 40362306a36Sopenharmony_ci !rds_conn_path_transition(cp, RDS_CONN_ERROR, 40462306a36Sopenharmony_ci RDS_CONN_DOWN)) { 40562306a36Sopenharmony_ci /* This can happen - eg when we're in the middle of tearing 40662306a36Sopenharmony_ci * down the connection, and someone unloads the rds module. 40762306a36Sopenharmony_ci * Quite reproducible with loopback connections. 40862306a36Sopenharmony_ci * Mostly harmless. 40962306a36Sopenharmony_ci * 41062306a36Sopenharmony_ci * Note that this also happens with rds-tcp because 41162306a36Sopenharmony_ci * we could have triggered rds_conn_path_drop in irq 41262306a36Sopenharmony_ci * mode from rds_tcp_state change on the receipt of 41362306a36Sopenharmony_ci * a FIN, thus we need to recheck for RDS_CONN_ERROR 41462306a36Sopenharmony_ci * here. 41562306a36Sopenharmony_ci */ 41662306a36Sopenharmony_ci rds_conn_path_error(cp, "%s: failed to transition " 41762306a36Sopenharmony_ci "to state DOWN, current state " 41862306a36Sopenharmony_ci "is %d\n", __func__, 41962306a36Sopenharmony_ci atomic_read(&cp->cp_state)); 42062306a36Sopenharmony_ci return; 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci /* Then reconnect if it's still live. 42562306a36Sopenharmony_ci * The passive side of an IB loopback connection is never added 42662306a36Sopenharmony_ci * to the conn hash, so we never trigger a reconnect on this 42762306a36Sopenharmony_ci * conn - the reconnect is always triggered by the active peer. */ 42862306a36Sopenharmony_ci cancel_delayed_work_sync(&cp->cp_conn_w); 42962306a36Sopenharmony_ci rcu_read_lock(); 43062306a36Sopenharmony_ci if (!hlist_unhashed(&conn->c_hash_node)) { 43162306a36Sopenharmony_ci rcu_read_unlock(); 43262306a36Sopenharmony_ci rds_queue_reconnect(cp); 43362306a36Sopenharmony_ci } else { 43462306a36Sopenharmony_ci rcu_read_unlock(); 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci/* destroy a single rds_conn_path. rds_conn_destroy() iterates over 43962306a36Sopenharmony_ci * all paths using rds_conn_path_destroy() 44062306a36Sopenharmony_ci */ 44162306a36Sopenharmony_cistatic void rds_conn_path_destroy(struct rds_conn_path *cp) 44262306a36Sopenharmony_ci{ 44362306a36Sopenharmony_ci struct rds_message *rm, *rtmp; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci if (!cp->cp_transport_data) 44662306a36Sopenharmony_ci return; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci /* make sure lingering queued work won't try to ref the conn */ 44962306a36Sopenharmony_ci cancel_delayed_work_sync(&cp->cp_send_w); 45062306a36Sopenharmony_ci cancel_delayed_work_sync(&cp->cp_recv_w); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci rds_conn_path_drop(cp, true); 45362306a36Sopenharmony_ci flush_work(&cp->cp_down_w); 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci /* tear down queued messages */ 45662306a36Sopenharmony_ci list_for_each_entry_safe(rm, rtmp, 45762306a36Sopenharmony_ci &cp->cp_send_queue, 45862306a36Sopenharmony_ci m_conn_item) { 45962306a36Sopenharmony_ci list_del_init(&rm->m_conn_item); 46062306a36Sopenharmony_ci BUG_ON(!list_empty(&rm->m_sock_item)); 46162306a36Sopenharmony_ci rds_message_put(rm); 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci if (cp->cp_xmit_rm) 46462306a36Sopenharmony_ci rds_message_put(cp->cp_xmit_rm); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci WARN_ON(delayed_work_pending(&cp->cp_send_w)); 46762306a36Sopenharmony_ci WARN_ON(delayed_work_pending(&cp->cp_recv_w)); 46862306a36Sopenharmony_ci WARN_ON(delayed_work_pending(&cp->cp_conn_w)); 46962306a36Sopenharmony_ci WARN_ON(work_pending(&cp->cp_down_w)); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci cp->cp_conn->c_trans->conn_free(cp->cp_transport_data); 47262306a36Sopenharmony_ci} 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci/* 47562306a36Sopenharmony_ci * Stop and free a connection. 47662306a36Sopenharmony_ci * 47762306a36Sopenharmony_ci * This can only be used in very limited circumstances. It assumes that once 47862306a36Sopenharmony_ci * the conn has been shutdown that no one else is referencing the connection. 47962306a36Sopenharmony_ci * We can only ensure this in the rmmod path in the current code. 48062306a36Sopenharmony_ci */ 48162306a36Sopenharmony_civoid rds_conn_destroy(struct rds_connection *conn) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci unsigned long flags; 48462306a36Sopenharmony_ci int i; 48562306a36Sopenharmony_ci struct rds_conn_path *cp; 48662306a36Sopenharmony_ci int npaths = (conn->c_trans->t_mp_capable ? RDS_MPATH_WORKERS : 1); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci rdsdebug("freeing conn %p for %pI4 -> " 48962306a36Sopenharmony_ci "%pI4\n", conn, &conn->c_laddr, 49062306a36Sopenharmony_ci &conn->c_faddr); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci /* Ensure conn will not be scheduled for reconnect */ 49362306a36Sopenharmony_ci spin_lock_irq(&rds_conn_lock); 49462306a36Sopenharmony_ci hlist_del_init_rcu(&conn->c_hash_node); 49562306a36Sopenharmony_ci spin_unlock_irq(&rds_conn_lock); 49662306a36Sopenharmony_ci synchronize_rcu(); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci /* shut the connection down */ 49962306a36Sopenharmony_ci for (i = 0; i < npaths; i++) { 50062306a36Sopenharmony_ci cp = &conn->c_path[i]; 50162306a36Sopenharmony_ci rds_conn_path_destroy(cp); 50262306a36Sopenharmony_ci BUG_ON(!list_empty(&cp->cp_retrans)); 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci /* 50662306a36Sopenharmony_ci * The congestion maps aren't freed up here. They're 50762306a36Sopenharmony_ci * freed by rds_cong_exit() after all the connections 50862306a36Sopenharmony_ci * have been freed. 50962306a36Sopenharmony_ci */ 51062306a36Sopenharmony_ci rds_cong_remove_conn(conn); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci kfree(conn->c_path); 51362306a36Sopenharmony_ci kmem_cache_free(rds_conn_slab, conn); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci spin_lock_irqsave(&rds_conn_lock, flags); 51662306a36Sopenharmony_ci rds_conn_count--; 51762306a36Sopenharmony_ci spin_unlock_irqrestore(&rds_conn_lock, flags); 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rds_conn_destroy); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_cistatic void __rds_inc_msg_cp(struct rds_incoming *inc, 52262306a36Sopenharmony_ci struct rds_info_iterator *iter, 52362306a36Sopenharmony_ci void *saddr, void *daddr, int flip, bool isv6) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 52662306a36Sopenharmony_ci if (isv6) 52762306a36Sopenharmony_ci rds6_inc_info_copy(inc, iter, saddr, daddr, flip); 52862306a36Sopenharmony_ci else 52962306a36Sopenharmony_ci#endif 53062306a36Sopenharmony_ci rds_inc_info_copy(inc, iter, *(__be32 *)saddr, 53162306a36Sopenharmony_ci *(__be32 *)daddr, flip); 53262306a36Sopenharmony_ci} 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_cistatic void rds_conn_message_info_cmn(struct socket *sock, unsigned int len, 53562306a36Sopenharmony_ci struct rds_info_iterator *iter, 53662306a36Sopenharmony_ci struct rds_info_lengths *lens, 53762306a36Sopenharmony_ci int want_send, bool isv6) 53862306a36Sopenharmony_ci{ 53962306a36Sopenharmony_ci struct hlist_head *head; 54062306a36Sopenharmony_ci struct list_head *list; 54162306a36Sopenharmony_ci struct rds_connection *conn; 54262306a36Sopenharmony_ci struct rds_message *rm; 54362306a36Sopenharmony_ci unsigned int total = 0; 54462306a36Sopenharmony_ci unsigned long flags; 54562306a36Sopenharmony_ci size_t i; 54662306a36Sopenharmony_ci int j; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci if (isv6) 54962306a36Sopenharmony_ci len /= sizeof(struct rds6_info_message); 55062306a36Sopenharmony_ci else 55162306a36Sopenharmony_ci len /= sizeof(struct rds_info_message); 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci rcu_read_lock(); 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci for (i = 0, head = rds_conn_hash; i < ARRAY_SIZE(rds_conn_hash); 55662306a36Sopenharmony_ci i++, head++) { 55762306a36Sopenharmony_ci hlist_for_each_entry_rcu(conn, head, c_hash_node) { 55862306a36Sopenharmony_ci struct rds_conn_path *cp; 55962306a36Sopenharmony_ci int npaths; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci if (!isv6 && conn->c_isv6) 56262306a36Sopenharmony_ci continue; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci npaths = (conn->c_trans->t_mp_capable ? 56562306a36Sopenharmony_ci RDS_MPATH_WORKERS : 1); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci for (j = 0; j < npaths; j++) { 56862306a36Sopenharmony_ci cp = &conn->c_path[j]; 56962306a36Sopenharmony_ci if (want_send) 57062306a36Sopenharmony_ci list = &cp->cp_send_queue; 57162306a36Sopenharmony_ci else 57262306a36Sopenharmony_ci list = &cp->cp_retrans; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci spin_lock_irqsave(&cp->cp_lock, flags); 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci /* XXX too lazy to maintain counts.. */ 57762306a36Sopenharmony_ci list_for_each_entry(rm, list, m_conn_item) { 57862306a36Sopenharmony_ci total++; 57962306a36Sopenharmony_ci if (total <= len) 58062306a36Sopenharmony_ci __rds_inc_msg_cp(&rm->m_inc, 58162306a36Sopenharmony_ci iter, 58262306a36Sopenharmony_ci &conn->c_laddr, 58362306a36Sopenharmony_ci &conn->c_faddr, 58462306a36Sopenharmony_ci 0, isv6); 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci spin_unlock_irqrestore(&cp->cp_lock, flags); 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci rcu_read_unlock(); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci lens->nr = total; 59462306a36Sopenharmony_ci if (isv6) 59562306a36Sopenharmony_ci lens->each = sizeof(struct rds6_info_message); 59662306a36Sopenharmony_ci else 59762306a36Sopenharmony_ci lens->each = sizeof(struct rds_info_message); 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_cistatic void rds_conn_message_info(struct socket *sock, unsigned int len, 60162306a36Sopenharmony_ci struct rds_info_iterator *iter, 60262306a36Sopenharmony_ci struct rds_info_lengths *lens, 60362306a36Sopenharmony_ci int want_send) 60462306a36Sopenharmony_ci{ 60562306a36Sopenharmony_ci rds_conn_message_info_cmn(sock, len, iter, lens, want_send, false); 60662306a36Sopenharmony_ci} 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 60962306a36Sopenharmony_cistatic void rds6_conn_message_info(struct socket *sock, unsigned int len, 61062306a36Sopenharmony_ci struct rds_info_iterator *iter, 61162306a36Sopenharmony_ci struct rds_info_lengths *lens, 61262306a36Sopenharmony_ci int want_send) 61362306a36Sopenharmony_ci{ 61462306a36Sopenharmony_ci rds_conn_message_info_cmn(sock, len, iter, lens, want_send, true); 61562306a36Sopenharmony_ci} 61662306a36Sopenharmony_ci#endif 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_cistatic void rds_conn_message_info_send(struct socket *sock, unsigned int len, 61962306a36Sopenharmony_ci struct rds_info_iterator *iter, 62062306a36Sopenharmony_ci struct rds_info_lengths *lens) 62162306a36Sopenharmony_ci{ 62262306a36Sopenharmony_ci rds_conn_message_info(sock, len, iter, lens, 1); 62362306a36Sopenharmony_ci} 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 62662306a36Sopenharmony_cistatic void rds6_conn_message_info_send(struct socket *sock, unsigned int len, 62762306a36Sopenharmony_ci struct rds_info_iterator *iter, 62862306a36Sopenharmony_ci struct rds_info_lengths *lens) 62962306a36Sopenharmony_ci{ 63062306a36Sopenharmony_ci rds6_conn_message_info(sock, len, iter, lens, 1); 63162306a36Sopenharmony_ci} 63262306a36Sopenharmony_ci#endif 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_cistatic void rds_conn_message_info_retrans(struct socket *sock, 63562306a36Sopenharmony_ci unsigned int len, 63662306a36Sopenharmony_ci struct rds_info_iterator *iter, 63762306a36Sopenharmony_ci struct rds_info_lengths *lens) 63862306a36Sopenharmony_ci{ 63962306a36Sopenharmony_ci rds_conn_message_info(sock, len, iter, lens, 0); 64062306a36Sopenharmony_ci} 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 64362306a36Sopenharmony_cistatic void rds6_conn_message_info_retrans(struct socket *sock, 64462306a36Sopenharmony_ci unsigned int len, 64562306a36Sopenharmony_ci struct rds_info_iterator *iter, 64662306a36Sopenharmony_ci struct rds_info_lengths *lens) 64762306a36Sopenharmony_ci{ 64862306a36Sopenharmony_ci rds6_conn_message_info(sock, len, iter, lens, 0); 64962306a36Sopenharmony_ci} 65062306a36Sopenharmony_ci#endif 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_civoid rds_for_each_conn_info(struct socket *sock, unsigned int len, 65362306a36Sopenharmony_ci struct rds_info_iterator *iter, 65462306a36Sopenharmony_ci struct rds_info_lengths *lens, 65562306a36Sopenharmony_ci int (*visitor)(struct rds_connection *, void *), 65662306a36Sopenharmony_ci u64 *buffer, 65762306a36Sopenharmony_ci size_t item_len) 65862306a36Sopenharmony_ci{ 65962306a36Sopenharmony_ci struct hlist_head *head; 66062306a36Sopenharmony_ci struct rds_connection *conn; 66162306a36Sopenharmony_ci size_t i; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci rcu_read_lock(); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci lens->nr = 0; 66662306a36Sopenharmony_ci lens->each = item_len; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci for (i = 0, head = rds_conn_hash; i < ARRAY_SIZE(rds_conn_hash); 66962306a36Sopenharmony_ci i++, head++) { 67062306a36Sopenharmony_ci hlist_for_each_entry_rcu(conn, head, c_hash_node) { 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci /* XXX no c_lock usage.. */ 67362306a36Sopenharmony_ci if (!visitor(conn, buffer)) 67462306a36Sopenharmony_ci continue; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci /* We copy as much as we can fit in the buffer, 67762306a36Sopenharmony_ci * but we count all items so that the caller 67862306a36Sopenharmony_ci * can resize the buffer. */ 67962306a36Sopenharmony_ci if (len >= item_len) { 68062306a36Sopenharmony_ci rds_info_copy(iter, buffer, item_len); 68162306a36Sopenharmony_ci len -= item_len; 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci lens->nr++; 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci } 68662306a36Sopenharmony_ci rcu_read_unlock(); 68762306a36Sopenharmony_ci} 68862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rds_for_each_conn_info); 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_cistatic void rds_walk_conn_path_info(struct socket *sock, unsigned int len, 69162306a36Sopenharmony_ci struct rds_info_iterator *iter, 69262306a36Sopenharmony_ci struct rds_info_lengths *lens, 69362306a36Sopenharmony_ci int (*visitor)(struct rds_conn_path *, void *), 69462306a36Sopenharmony_ci u64 *buffer, 69562306a36Sopenharmony_ci size_t item_len) 69662306a36Sopenharmony_ci{ 69762306a36Sopenharmony_ci struct hlist_head *head; 69862306a36Sopenharmony_ci struct rds_connection *conn; 69962306a36Sopenharmony_ci size_t i; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci rcu_read_lock(); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci lens->nr = 0; 70462306a36Sopenharmony_ci lens->each = item_len; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci for (i = 0, head = rds_conn_hash; i < ARRAY_SIZE(rds_conn_hash); 70762306a36Sopenharmony_ci i++, head++) { 70862306a36Sopenharmony_ci hlist_for_each_entry_rcu(conn, head, c_hash_node) { 70962306a36Sopenharmony_ci struct rds_conn_path *cp; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci /* XXX We only copy the information from the first 71262306a36Sopenharmony_ci * path for now. The problem is that if there are 71362306a36Sopenharmony_ci * more than one underlying paths, we cannot report 71462306a36Sopenharmony_ci * information of all of them using the existing 71562306a36Sopenharmony_ci * API. For example, there is only one next_tx_seq, 71662306a36Sopenharmony_ci * which path's next_tx_seq should we report? It is 71762306a36Sopenharmony_ci * a bug in the design of MPRDS. 71862306a36Sopenharmony_ci */ 71962306a36Sopenharmony_ci cp = conn->c_path; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci /* XXX no cp_lock usage.. */ 72262306a36Sopenharmony_ci if (!visitor(cp, buffer)) 72362306a36Sopenharmony_ci continue; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci /* We copy as much as we can fit in the buffer, 72662306a36Sopenharmony_ci * but we count all items so that the caller 72762306a36Sopenharmony_ci * can resize the buffer. 72862306a36Sopenharmony_ci */ 72962306a36Sopenharmony_ci if (len >= item_len) { 73062306a36Sopenharmony_ci rds_info_copy(iter, buffer, item_len); 73162306a36Sopenharmony_ci len -= item_len; 73262306a36Sopenharmony_ci } 73362306a36Sopenharmony_ci lens->nr++; 73462306a36Sopenharmony_ci } 73562306a36Sopenharmony_ci } 73662306a36Sopenharmony_ci rcu_read_unlock(); 73762306a36Sopenharmony_ci} 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_cistatic int rds_conn_info_visitor(struct rds_conn_path *cp, void *buffer) 74062306a36Sopenharmony_ci{ 74162306a36Sopenharmony_ci struct rds_info_connection *cinfo = buffer; 74262306a36Sopenharmony_ci struct rds_connection *conn = cp->cp_conn; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci if (conn->c_isv6) 74562306a36Sopenharmony_ci return 0; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci cinfo->next_tx_seq = cp->cp_next_tx_seq; 74862306a36Sopenharmony_ci cinfo->next_rx_seq = cp->cp_next_rx_seq; 74962306a36Sopenharmony_ci cinfo->laddr = conn->c_laddr.s6_addr32[3]; 75062306a36Sopenharmony_ci cinfo->faddr = conn->c_faddr.s6_addr32[3]; 75162306a36Sopenharmony_ci cinfo->tos = conn->c_tos; 75262306a36Sopenharmony_ci strncpy(cinfo->transport, conn->c_trans->t_name, 75362306a36Sopenharmony_ci sizeof(cinfo->transport)); 75462306a36Sopenharmony_ci cinfo->flags = 0; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci rds_conn_info_set(cinfo->flags, test_bit(RDS_IN_XMIT, &cp->cp_flags), 75762306a36Sopenharmony_ci SENDING); 75862306a36Sopenharmony_ci /* XXX Future: return the state rather than these funky bits */ 75962306a36Sopenharmony_ci rds_conn_info_set(cinfo->flags, 76062306a36Sopenharmony_ci atomic_read(&cp->cp_state) == RDS_CONN_CONNECTING, 76162306a36Sopenharmony_ci CONNECTING); 76262306a36Sopenharmony_ci rds_conn_info_set(cinfo->flags, 76362306a36Sopenharmony_ci atomic_read(&cp->cp_state) == RDS_CONN_UP, 76462306a36Sopenharmony_ci CONNECTED); 76562306a36Sopenharmony_ci return 1; 76662306a36Sopenharmony_ci} 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 76962306a36Sopenharmony_cistatic int rds6_conn_info_visitor(struct rds_conn_path *cp, void *buffer) 77062306a36Sopenharmony_ci{ 77162306a36Sopenharmony_ci struct rds6_info_connection *cinfo6 = buffer; 77262306a36Sopenharmony_ci struct rds_connection *conn = cp->cp_conn; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci cinfo6->next_tx_seq = cp->cp_next_tx_seq; 77562306a36Sopenharmony_ci cinfo6->next_rx_seq = cp->cp_next_rx_seq; 77662306a36Sopenharmony_ci cinfo6->laddr = conn->c_laddr; 77762306a36Sopenharmony_ci cinfo6->faddr = conn->c_faddr; 77862306a36Sopenharmony_ci strncpy(cinfo6->transport, conn->c_trans->t_name, 77962306a36Sopenharmony_ci sizeof(cinfo6->transport)); 78062306a36Sopenharmony_ci cinfo6->flags = 0; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci rds_conn_info_set(cinfo6->flags, test_bit(RDS_IN_XMIT, &cp->cp_flags), 78362306a36Sopenharmony_ci SENDING); 78462306a36Sopenharmony_ci /* XXX Future: return the state rather than these funky bits */ 78562306a36Sopenharmony_ci rds_conn_info_set(cinfo6->flags, 78662306a36Sopenharmony_ci atomic_read(&cp->cp_state) == RDS_CONN_CONNECTING, 78762306a36Sopenharmony_ci CONNECTING); 78862306a36Sopenharmony_ci rds_conn_info_set(cinfo6->flags, 78962306a36Sopenharmony_ci atomic_read(&cp->cp_state) == RDS_CONN_UP, 79062306a36Sopenharmony_ci CONNECTED); 79162306a36Sopenharmony_ci /* Just return 1 as there is no error case. This is a helper function 79262306a36Sopenharmony_ci * for rds_walk_conn_path_info() and it wants a return value. 79362306a36Sopenharmony_ci */ 79462306a36Sopenharmony_ci return 1; 79562306a36Sopenharmony_ci} 79662306a36Sopenharmony_ci#endif 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_cistatic void rds_conn_info(struct socket *sock, unsigned int len, 79962306a36Sopenharmony_ci struct rds_info_iterator *iter, 80062306a36Sopenharmony_ci struct rds_info_lengths *lens) 80162306a36Sopenharmony_ci{ 80262306a36Sopenharmony_ci u64 buffer[(sizeof(struct rds_info_connection) + 7) / 8]; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci rds_walk_conn_path_info(sock, len, iter, lens, 80562306a36Sopenharmony_ci rds_conn_info_visitor, 80662306a36Sopenharmony_ci buffer, 80762306a36Sopenharmony_ci sizeof(struct rds_info_connection)); 80862306a36Sopenharmony_ci} 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 81162306a36Sopenharmony_cistatic void rds6_conn_info(struct socket *sock, unsigned int len, 81262306a36Sopenharmony_ci struct rds_info_iterator *iter, 81362306a36Sopenharmony_ci struct rds_info_lengths *lens) 81462306a36Sopenharmony_ci{ 81562306a36Sopenharmony_ci u64 buffer[(sizeof(struct rds6_info_connection) + 7) / 8]; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci rds_walk_conn_path_info(sock, len, iter, lens, 81862306a36Sopenharmony_ci rds6_conn_info_visitor, 81962306a36Sopenharmony_ci buffer, 82062306a36Sopenharmony_ci sizeof(struct rds6_info_connection)); 82162306a36Sopenharmony_ci} 82262306a36Sopenharmony_ci#endif 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ciint rds_conn_init(void) 82562306a36Sopenharmony_ci{ 82662306a36Sopenharmony_ci int ret; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci ret = rds_loop_net_init(); /* register pernet callback */ 82962306a36Sopenharmony_ci if (ret) 83062306a36Sopenharmony_ci return ret; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci rds_conn_slab = kmem_cache_create("rds_connection", 83362306a36Sopenharmony_ci sizeof(struct rds_connection), 83462306a36Sopenharmony_ci 0, 0, NULL); 83562306a36Sopenharmony_ci if (!rds_conn_slab) { 83662306a36Sopenharmony_ci rds_loop_net_exit(); 83762306a36Sopenharmony_ci return -ENOMEM; 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci rds_info_register_func(RDS_INFO_CONNECTIONS, rds_conn_info); 84162306a36Sopenharmony_ci rds_info_register_func(RDS_INFO_SEND_MESSAGES, 84262306a36Sopenharmony_ci rds_conn_message_info_send); 84362306a36Sopenharmony_ci rds_info_register_func(RDS_INFO_RETRANS_MESSAGES, 84462306a36Sopenharmony_ci rds_conn_message_info_retrans); 84562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 84662306a36Sopenharmony_ci rds_info_register_func(RDS6_INFO_CONNECTIONS, rds6_conn_info); 84762306a36Sopenharmony_ci rds_info_register_func(RDS6_INFO_SEND_MESSAGES, 84862306a36Sopenharmony_ci rds6_conn_message_info_send); 84962306a36Sopenharmony_ci rds_info_register_func(RDS6_INFO_RETRANS_MESSAGES, 85062306a36Sopenharmony_ci rds6_conn_message_info_retrans); 85162306a36Sopenharmony_ci#endif 85262306a36Sopenharmony_ci return 0; 85362306a36Sopenharmony_ci} 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_civoid rds_conn_exit(void) 85662306a36Sopenharmony_ci{ 85762306a36Sopenharmony_ci rds_loop_net_exit(); /* unregister pernet callback */ 85862306a36Sopenharmony_ci rds_loop_exit(); 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci WARN_ON(!hlist_empty(rds_conn_hash)); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci kmem_cache_destroy(rds_conn_slab); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci rds_info_deregister_func(RDS_INFO_CONNECTIONS, rds_conn_info); 86562306a36Sopenharmony_ci rds_info_deregister_func(RDS_INFO_SEND_MESSAGES, 86662306a36Sopenharmony_ci rds_conn_message_info_send); 86762306a36Sopenharmony_ci rds_info_deregister_func(RDS_INFO_RETRANS_MESSAGES, 86862306a36Sopenharmony_ci rds_conn_message_info_retrans); 86962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 87062306a36Sopenharmony_ci rds_info_deregister_func(RDS6_INFO_CONNECTIONS, rds6_conn_info); 87162306a36Sopenharmony_ci rds_info_deregister_func(RDS6_INFO_SEND_MESSAGES, 87262306a36Sopenharmony_ci rds6_conn_message_info_send); 87362306a36Sopenharmony_ci rds_info_deregister_func(RDS6_INFO_RETRANS_MESSAGES, 87462306a36Sopenharmony_ci rds6_conn_message_info_retrans); 87562306a36Sopenharmony_ci#endif 87662306a36Sopenharmony_ci} 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci/* 87962306a36Sopenharmony_ci * Force a disconnect 88062306a36Sopenharmony_ci */ 88162306a36Sopenharmony_civoid rds_conn_path_drop(struct rds_conn_path *cp, bool destroy) 88262306a36Sopenharmony_ci{ 88362306a36Sopenharmony_ci atomic_set(&cp->cp_state, RDS_CONN_ERROR); 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci rcu_read_lock(); 88662306a36Sopenharmony_ci if (!destroy && rds_destroy_pending(cp->cp_conn)) { 88762306a36Sopenharmony_ci rcu_read_unlock(); 88862306a36Sopenharmony_ci return; 88962306a36Sopenharmony_ci } 89062306a36Sopenharmony_ci queue_work(rds_wq, &cp->cp_down_w); 89162306a36Sopenharmony_ci rcu_read_unlock(); 89262306a36Sopenharmony_ci} 89362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rds_conn_path_drop); 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_civoid rds_conn_drop(struct rds_connection *conn) 89662306a36Sopenharmony_ci{ 89762306a36Sopenharmony_ci WARN_ON(conn->c_trans->t_mp_capable); 89862306a36Sopenharmony_ci rds_conn_path_drop(&conn->c_path[0], false); 89962306a36Sopenharmony_ci} 90062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rds_conn_drop); 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci/* 90362306a36Sopenharmony_ci * If the connection is down, trigger a connect. We may have scheduled a 90462306a36Sopenharmony_ci * delayed reconnect however - in this case we should not interfere. 90562306a36Sopenharmony_ci */ 90662306a36Sopenharmony_civoid rds_conn_path_connect_if_down(struct rds_conn_path *cp) 90762306a36Sopenharmony_ci{ 90862306a36Sopenharmony_ci rcu_read_lock(); 90962306a36Sopenharmony_ci if (rds_destroy_pending(cp->cp_conn)) { 91062306a36Sopenharmony_ci rcu_read_unlock(); 91162306a36Sopenharmony_ci return; 91262306a36Sopenharmony_ci } 91362306a36Sopenharmony_ci if (rds_conn_path_state(cp) == RDS_CONN_DOWN && 91462306a36Sopenharmony_ci !test_and_set_bit(RDS_RECONNECT_PENDING, &cp->cp_flags)) 91562306a36Sopenharmony_ci queue_delayed_work(rds_wq, &cp->cp_conn_w, 0); 91662306a36Sopenharmony_ci rcu_read_unlock(); 91762306a36Sopenharmony_ci} 91862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rds_conn_path_connect_if_down); 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci/* Check connectivity of all paths 92162306a36Sopenharmony_ci */ 92262306a36Sopenharmony_civoid rds_check_all_paths(struct rds_connection *conn) 92362306a36Sopenharmony_ci{ 92462306a36Sopenharmony_ci int i = 0; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci do { 92762306a36Sopenharmony_ci rds_conn_path_connect_if_down(&conn->c_path[i]); 92862306a36Sopenharmony_ci } while (++i < conn->c_npaths); 92962306a36Sopenharmony_ci} 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_civoid rds_conn_connect_if_down(struct rds_connection *conn) 93262306a36Sopenharmony_ci{ 93362306a36Sopenharmony_ci WARN_ON(conn->c_trans->t_mp_capable); 93462306a36Sopenharmony_ci rds_conn_path_connect_if_down(&conn->c_path[0]); 93562306a36Sopenharmony_ci} 93662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rds_conn_connect_if_down); 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_civoid 93962306a36Sopenharmony_ci__rds_conn_path_error(struct rds_conn_path *cp, const char *fmt, ...) 94062306a36Sopenharmony_ci{ 94162306a36Sopenharmony_ci va_list ap; 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci va_start(ap, fmt); 94462306a36Sopenharmony_ci vprintk(fmt, ap); 94562306a36Sopenharmony_ci va_end(ap); 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci rds_conn_path_drop(cp, false); 94862306a36Sopenharmony_ci} 949