10fbc78cbSAndy Grover /*
2eee2fa6aSKa-Cheong Poon * Copyright (c) 2006, 2017 Oracle and/or its affiliates. All rights reserved.
30fbc78cbSAndy Grover *
40fbc78cbSAndy Grover * This software is available to you under a choice of one of two
50fbc78cbSAndy Grover * licenses. You may choose to be licensed under the terms of the GNU
60fbc78cbSAndy Grover * General Public License (GPL) Version 2, available from the file
70fbc78cbSAndy Grover * COPYING in the main directory of this source tree, or the
80fbc78cbSAndy Grover * OpenIB.org BSD license below:
90fbc78cbSAndy Grover *
100fbc78cbSAndy Grover * Redistribution and use in source and binary forms, with or
110fbc78cbSAndy Grover * without modification, are permitted provided that the following
120fbc78cbSAndy Grover * conditions are met:
130fbc78cbSAndy Grover *
140fbc78cbSAndy Grover * - Redistributions of source code must retain the above
150fbc78cbSAndy Grover * copyright notice, this list of conditions and the following
160fbc78cbSAndy Grover * disclaimer.
170fbc78cbSAndy Grover *
180fbc78cbSAndy Grover * - Redistributions in binary form must reproduce the above
190fbc78cbSAndy Grover * copyright notice, this list of conditions and the following
200fbc78cbSAndy Grover * disclaimer in the documentation and/or other materials
210fbc78cbSAndy Grover * provided with the distribution.
220fbc78cbSAndy Grover *
230fbc78cbSAndy Grover * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
240fbc78cbSAndy Grover * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
250fbc78cbSAndy Grover * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
260fbc78cbSAndy Grover * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
270fbc78cbSAndy Grover * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
280fbc78cbSAndy Grover * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
290fbc78cbSAndy Grover * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
300fbc78cbSAndy Grover * SOFTWARE.
310fbc78cbSAndy Grover *
320fbc78cbSAndy Grover */
330fbc78cbSAndy Grover #include <linux/kernel.h>
340fbc78cbSAndy Grover #include <linux/module.h>
350fbc78cbSAndy Grover #include <linux/in.h>
36eee2fa6aSKa-Cheong Poon #include <linux/ipv6.h>
370fbc78cbSAndy Grover
380fbc78cbSAndy Grover #include "rds.h"
390fbc78cbSAndy Grover #include "loop.h"
400fbc78cbSAndy Grover
41*4c342f77SRao Shoaib static char * const rds_trans_modules[] = {
42*4c342f77SRao Shoaib [RDS_TRANS_IB] = "rds_rdma",
43*4c342f77SRao Shoaib [RDS_TRANS_GAP] = NULL,
44*4c342f77SRao Shoaib [RDS_TRANS_TCP] = "rds_tcp",
45*4c342f77SRao Shoaib };
46*4c342f77SRao Shoaib
47335776bdSAndy Grover static struct rds_transport *transports[RDS_TRANS_COUNT];
480fbc78cbSAndy Grover static DECLARE_RWSEM(rds_trans_sem);
490fbc78cbSAndy Grover
rds_trans_register(struct rds_transport * trans)50a8d63a53SZhu Yanjun void rds_trans_register(struct rds_transport *trans)
510fbc78cbSAndy Grover {
520fbc78cbSAndy Grover BUG_ON(strlen(trans->t_name) + 1 > TRANSNAMSIZ);
530fbc78cbSAndy Grover
540fbc78cbSAndy Grover down_write(&rds_trans_sem);
550fbc78cbSAndy Grover
56335776bdSAndy Grover if (transports[trans->t_type])
57335776bdSAndy Grover printk(KERN_ERR "RDS Transport type %d already registered\n",
58335776bdSAndy Grover trans->t_type);
59335776bdSAndy Grover else {
60335776bdSAndy Grover transports[trans->t_type] = trans;
610fbc78cbSAndy Grover printk(KERN_INFO "Registered RDS/%s transport\n", trans->t_name);
62335776bdSAndy Grover }
630fbc78cbSAndy Grover
640fbc78cbSAndy Grover up_write(&rds_trans_sem);
650fbc78cbSAndy Grover }
66616b757aSAndy Grover EXPORT_SYMBOL_GPL(rds_trans_register);
670fbc78cbSAndy Grover
rds_trans_unregister(struct rds_transport * trans)680fbc78cbSAndy Grover void rds_trans_unregister(struct rds_transport *trans)
690fbc78cbSAndy Grover {
700fbc78cbSAndy Grover down_write(&rds_trans_sem);
710fbc78cbSAndy Grover
72335776bdSAndy Grover transports[trans->t_type] = NULL;
730fbc78cbSAndy Grover printk(KERN_INFO "Unregistered RDS/%s transport\n", trans->t_name);
740fbc78cbSAndy Grover
750fbc78cbSAndy Grover up_write(&rds_trans_sem);
760fbc78cbSAndy Grover }
77616b757aSAndy Grover EXPORT_SYMBOL_GPL(rds_trans_unregister);
780fbc78cbSAndy Grover
rds_trans_put(struct rds_transport * trans)795adb5bc6SZach Brown void rds_trans_put(struct rds_transport *trans)
805adb5bc6SZach Brown {
81f6e1c916SMarkus Elfring if (trans)
825adb5bc6SZach Brown module_put(trans->t_owner);
835adb5bc6SZach Brown }
845adb5bc6SZach Brown
rds_trans_get_preferred(struct net * net,const struct in6_addr * addr,__u32 scope_id)85eee2fa6aSKa-Cheong Poon struct rds_transport *rds_trans_get_preferred(struct net *net,
86eee2fa6aSKa-Cheong Poon const struct in6_addr *addr,
87eee2fa6aSKa-Cheong Poon __u32 scope_id)
880fbc78cbSAndy Grover {
890fbc78cbSAndy Grover struct rds_transport *ret = NULL;
905adb5bc6SZach Brown struct rds_transport *trans;
915adb5bc6SZach Brown unsigned int i;
920fbc78cbSAndy Grover
93eee2fa6aSKa-Cheong Poon if (ipv6_addr_v4mapped(addr)) {
94eee2fa6aSKa-Cheong Poon if (*(u_int8_t *)&addr->s6_addr32[3] == IN_LOOPBACKNET)
950fbc78cbSAndy Grover return &rds_loop_transport;
96eee2fa6aSKa-Cheong Poon } else if (ipv6_addr_loopback(addr)) {
97eee2fa6aSKa-Cheong Poon return &rds_loop_transport;
98eee2fa6aSKa-Cheong Poon }
990fbc78cbSAndy Grover
1000fbc78cbSAndy Grover down_read(&rds_trans_sem);
1015adb5bc6SZach Brown for (i = 0; i < RDS_TRANS_COUNT; i++) {
1025adb5bc6SZach Brown trans = transports[i];
1035adb5bc6SZach Brown
104eee2fa6aSKa-Cheong Poon if (trans && (trans->laddr_check(net, addr, scope_id) == 0) &&
1055adb5bc6SZach Brown (!trans->t_owner || try_module_get(trans->t_owner))) {
1065adb5bc6SZach Brown ret = trans;
1070fbc78cbSAndy Grover break;
1080fbc78cbSAndy Grover }
1090fbc78cbSAndy Grover }
1100fbc78cbSAndy Grover up_read(&rds_trans_sem);
1110fbc78cbSAndy Grover
1120fbc78cbSAndy Grover return ret;
1130fbc78cbSAndy Grover }
1140fbc78cbSAndy Grover
rds_trans_get(int t_type)115d97dac54SSowmini Varadhan struct rds_transport *rds_trans_get(int t_type)
116d97dac54SSowmini Varadhan {
117d97dac54SSowmini Varadhan struct rds_transport *ret = NULL;
118d97dac54SSowmini Varadhan struct rds_transport *trans;
119d97dac54SSowmini Varadhan
120d97dac54SSowmini Varadhan down_read(&rds_trans_sem);
121*4c342f77SRao Shoaib trans = transports[t_type];
122*4c342f77SRao Shoaib if (!trans) {
123*4c342f77SRao Shoaib up_read(&rds_trans_sem);
124*4c342f77SRao Shoaib if (rds_trans_modules[t_type])
125*4c342f77SRao Shoaib request_module(rds_trans_modules[t_type]);
126*4c342f77SRao Shoaib down_read(&rds_trans_sem);
127*4c342f77SRao Shoaib trans = transports[t_type];
128*4c342f77SRao Shoaib }
129d97dac54SSowmini Varadhan if (trans && trans->t_type == t_type &&
130*4c342f77SRao Shoaib (!trans->t_owner || try_module_get(trans->t_owner)))
131d97dac54SSowmini Varadhan ret = trans;
132*4c342f77SRao Shoaib
133d97dac54SSowmini Varadhan up_read(&rds_trans_sem);
134d97dac54SSowmini Varadhan
135d97dac54SSowmini Varadhan return ret;
136d97dac54SSowmini Varadhan }
137d97dac54SSowmini Varadhan
1380fbc78cbSAndy Grover /*
1390fbc78cbSAndy Grover * This returns the number of stats entries in the snapshot and only
1400fbc78cbSAndy Grover * copies them using the iter if there is enough space for them. The
1410fbc78cbSAndy Grover * caller passes in the global stats so that we can size and copy while
1420fbc78cbSAndy Grover * holding the lock.
1430fbc78cbSAndy Grover */
rds_trans_stats_info_copy(struct rds_info_iterator * iter,unsigned int avail)1440fbc78cbSAndy Grover unsigned int rds_trans_stats_info_copy(struct rds_info_iterator *iter,
1450fbc78cbSAndy Grover unsigned int avail)
1460fbc78cbSAndy Grover
1470fbc78cbSAndy Grover {
1480fbc78cbSAndy Grover struct rds_transport *trans;
1490fbc78cbSAndy Grover unsigned int total = 0;
1500fbc78cbSAndy Grover unsigned int part;
151335776bdSAndy Grover int i;
1520fbc78cbSAndy Grover
1530fbc78cbSAndy Grover rds_info_iter_unmap(iter);
1540fbc78cbSAndy Grover down_read(&rds_trans_sem);
1550fbc78cbSAndy Grover
1565c3da57dSJoshua Houghton for (i = 0; i < RDS_TRANS_COUNT; i++) {
157335776bdSAndy Grover trans = transports[i];
158335776bdSAndy Grover if (!trans || !trans->stats_info_copy)
1590fbc78cbSAndy Grover continue;
1600fbc78cbSAndy Grover
1610fbc78cbSAndy Grover part = trans->stats_info_copy(iter, avail);
1620fbc78cbSAndy Grover avail -= min(avail, part);
1630fbc78cbSAndy Grover total += part;
1640fbc78cbSAndy Grover }
1650fbc78cbSAndy Grover
1660fbc78cbSAndy Grover up_read(&rds_trans_sem);
1670fbc78cbSAndy Grover
1680fbc78cbSAndy Grover return total;
1690fbc78cbSAndy Grover }
170