cong.c revision 6e18d381c642549b8bb1774a803d3510aec6baaf
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
/*
* Copyright (c) 2007 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
* 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.
*
*/
/*
* This file implements the receive side of the unconventional congestion
* management in RDS.
*
* Messages waiting in the receive queue on the receiving socket are accounted
* against the sockets SO_RCVBUF option value. Only the payload bytes in the
* message are accounted for. If the number of bytes queued equals or exceeds
* rcvbuf then the socket is congested. All sends attempted to this socket's
* address should return block or return -EWOULDBLOCK.
*
* Applications are expected to be reasonably tuned such that this situation
* very rarely occurs. An application encountering this "back-pressure" is
* considered a bug.
*
* This is implemented by having each node maintain bitmaps which indicate
* which ports on bound addresses are congested. As the bitmap changes it is
* sent through all the connections which terminate in the local address of the
* bitmap which changed.
*
* The bitmaps are allocated as connections are brought up. This avoids
* allocation in the interrupt handling path which queues messages on sockets.
* The dense bitmaps let transports send the entire bitmap on any bitmap change
* reasonably efficiently. This is much easier to implement than some
* finer-grained communication of per-port congestion. The sender does a very
* inexpensive bit test to test if the port it's about to send to is congested
* or not.
*/
/*
* Interaction with poll is a tad tricky. We want all processes stuck in
* poll to wake up and check whether a congested destination became uncongested.
* The really sad thing is we have no idea which destinations the application
* wants to send to - we don't even know which rdsv3_connections are involved.
* So until we implement a more flexible rds poll interface, we have to make
* do with this:
* We maintain a global counter that is incremented each time a congestion map
* update is received. Each rds socket tracks this value, and if rdsv3_poll
* finds that the saved generation number is smaller than the global generation
* number, it wakes up the process.
*/
/*
* Congestion monitoring
*/
static struct list rdsv3_cong_monitor;
static krwlock_t rdsv3_cong_monitor_lock;
/*
* Yes, a global lock. It's used so infrequently that it's worth keeping it
* global to simplify the locking. It's only used in the following
* circumstances:
*
* - on connection buildup to associate a conn with its maps
* - on map changes to inform conns of a new map to send
*
* It's sadly ordered under the socket callback lock and the connection lock.
* Receive paths can mark ports congested from interrupt context so the
* lock masks interrupts.
*/
static kmutex_t rdsv3_cong_lock;
static struct avl_tree rdsv3_cong_tree;
static struct rdsv3_cong_map *
{
struct rdsv3_cong_map *map;
if (insert) {
return (NULL);
}
} else {
struct rdsv3_cong_map map1;
}
return (map);
}
/*
* There is only ever one bitmap for any address. Connections try and allocate
* these bitmaps in the process getting pointers to them. The bitmaps are only
* ever freed as the module is removed after all connections have been freed.
*/
static struct rdsv3_cong_map *
{
struct rdsv3_cong_map *map;
unsigned long zp;
unsigned long i;
return (NULL);
for (i = 0; i < RDSV3_CONG_MAP_PAGES; i++) {
if (zp == 0)
goto out;
}
}
out:
if (map) {
i++)
}
return (ret);
}
/*
* Put the conn on its local map's list. This is called when the conn is
* really added to the hash. It's nested under the rdsv3_conn_lock, sadly.
*/
void
{
}
void
{
}
int
{
return (-ENOMEM);
return (0);
}
void
{
struct rdsv3_connection *conn;
}
}
}
void
{
RDSV3_DPRINTF4("rdsv3_cong_map_updated",
"waking map %p for %u.%u.%u.%u",
#if 0
#endif
struct rdsv3_sock *rs;
rs_cong_list) {
if (rs->rs_cong_notify)
}
}
}
int
rdsv3_cong_updated_since(unsigned long *recent)
{
return (0);
return (1);
}
/*
* These should be using generic_{test,__{clear,set}}_le_bit() but some old
* kernels don't have them. Sigh.
*/
#if defined(sparc)
#else
#define LE_BIT_XOR 0
#endif
/*
* We're called under the locking that protects the sockets receive buffer
* consumption. This makes it a lot easier for the caller to only call us
* when it knows that an existing set bit needs to be cleared, and vice versa.
* We can't block and we need to deal with concurrent sockets working against
* the same per-address map.
*/
void
{
unsigned long i;
unsigned long off;
RDSV3_DPRINTF4("rdsv3_cong_set_bit",
"setting congestion for %u.%u.%u.%u:%u in map %p",
}
void
{
unsigned long i;
unsigned long off;
RDSV3_DPRINTF4("rdsv3_cong_clear_bit",
"clearing congestion for %u.%u.%u.%u:%u in map %p\n",
}
static int
{
unsigned long i;
unsigned long off;
}
void
{
}
void
{
struct rdsv3_cong_map *map;
/* update congestion map for now-closed port */
}
}
int
struct rdsv3_sock *rs)
{
int ret = 0;
return (0);
if (nonblock) {
/*
* It would have been nice to have an atomic set_bit on
* a uint64_t.
*/
rs->rs_cong_mask |=
/*
* Test again - a congestion update may have arrived in
* the meantime.
*/
return (0);
}
return (-ENOBUFS);
}
#if 0
if (ret == 0)
return (-ERESTART);
return (0);
#else
if (ret == 0) {
break;
}
}
return (ret);
#endif
}
void
rdsv3_cong_exit(void)
{
struct rdsv3_cong_map *map;
unsigned long i;
i++)
}
}
/*
* Allocate a RDS message containing a congestion update.
*/
struct rdsv3_message *
{
struct rdsv3_message *rm;
return (rm);
}
static int
{
return (-1);
return (1);
return (0);
}
void
rdsv3_cong_init(void)
{
m_rb_node));
}