/*
* 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 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* General Soft rings - Simulating Rx rings in S/W.
*
* Soft ring is a data abstraction containing a queue and a worker
* thread and represents a hardware Rx ring in software. Each soft
* ring set can have a collection of soft rings for separating
* allowing a higher degree of parallelism by sending traffic to
* one of the soft rings for a SRS (using a hash on src IP or port).
* Each soft ring worker thread can be bound to a different CPU
* allowing the processing for each soft ring to happen in parallel
* and independent from each other.
*
* Protocol soft rings:
*
* Each SRS has at an minimum 3 softrings. One each for IPv4 TCP,
* IPv4 UDP and rest (OTH - for IPv6 and everything else). The
* SRS does dynamic polling and enforces link level bandwidth but
* it does so for all traffic (IPv4 and IPv6 and all protocols) on
* that link. However, each protocol layer wants a different
* behaviour. For instance IPv4 TCP has per CPU squeues which
* enforce their own polling and flow control so IPv4 TCP traffic
* needs to go to a separate soft ring which can be polled by the
* TCP squeue. It also allows TCP squeue to push back flow control
* all the way to NIC hardware (if it puts its corresponding soft
* ring in the poll mode and soft ring queue builds up, the
* shared srs_poll_pkt_cnt goes up and SRS automatically stops
* more packets from entering the system).
*
* Similarly, the UDP benefits from a DLS bypass and packet chaining
* so sending it to a separate soft ring is desired. All the rest of
* the traffic (including IPv6 is sent to OTH softring). The IPv6
* traffic current goes through OTH softring and via DLS because
* it need more processing to be done. Irrespective of the sap
* (IPv4 or IPv6) or the transport, the dynamic polling, B/W enforcement,
* cpu assignment, fanout, etc apply to all traffic since they
* are implement by the SRS which is agnostic to sap or transport.
*
* Fanout soft rings:
*
* On a multithreaded system, we can assign more CPU and multi thread
* the stack by creating a soft ring per CPU and spreading traffic
* based on a hash computed on src IP etc. Since we still need to
* keep the protocol separation, we create a set of 3 soft ring per
* CPU (specified by cpu list or degree of fanout).
*
* NOTE: See the block level comment on top of mac_sched.c
*/
#include <inet/ipsec_impl.h>
#include <inet/ipsecesp.h>
#include <sys/mac_impl.h>
#include <sys/mac_client_impl.h>
#include <sys/mac_soft_ring.h>
#include <sys/mac_flow_impl.h>
#include <sys/mac_stat.h>
static void mac_rx_soft_ring_drain(mac_soft_ring_t *);
static void mac_soft_ring_fire(void *);
static void mac_soft_ring_worker(mac_soft_ring_t *);
static void mac_tx_soft_ring_drain(mac_soft_ring_t *);
extern kmem_cache_t *mac_soft_ring_cache;
} else { \
/* ADD to the list */ \
softring->s_ring_prev = \
} \
mac_srs->srs_soft_ring_count++; \
}
/*
* mac_soft_ring_worker_wakeup
*
* Wake up the soft ring worker thread to process the queue as long
* as no one else is processing it and upper layer (client) is still
* ready to receive packets.
*/
void
{
if (ringp->s_ring_wait != 0) {
ringp->s_ring_tid =
ringp->s_ring_wait);
} else {
/* Schedule the worker thread. */
}
}
}
/*
* mac_soft_ring_create
*
* Create a soft ring, do the necessary setup and bind the worker
* thread to the assigned CPU.
*/
{
if (type & ST_RING_TCP) {
} else if (type & ST_RING_UDP) {
} else if (type & ST_RING_OTH) {
} else {
}
/*
* Protect against access from DR callbacks (mac_walk_srs_bind/unbind)
* which can't grab the mac perimeter
*/
/*
* set the bind CPU to -1 to indicate
* no thread affinity set
*/
if (type & ST_RING_TX) {
}
} else {
}
if (cpuid != -1)
return (ringp);
}
/*
* mac_soft_ring_free
*
* Free the soft ring once we are done with it.
*/
void
{
}
/*
* mac_soft_ring_bind
*
* Bind a soft ring worker thread to supplied CPU.
*/
cpu_t *
{
if (mac_soft_ring_thread_bind == 0) {
mac_soft_ring_t *, ringp);
return (NULL);
}
return (NULL);
if (clear)
return (cp);
}
/*
* mac_soft_ring_unbind
*
* Un Bind a soft ring worker thread.
*/
void
{
return;
}
}
/*
* PRIVATE FUNCTIONS
*/
static void
{
if (ringp->s_ring_tid == 0) {
return;
}
ringp->s_ring_tid = 0;
}
}
/*
* mac_rx_soft_ring_drain
*
* Called when worker thread model (ST_RING_WORKER_ONLY) of processing
* incoming packets is used. s_ring_first contain the queued packets.
* s_ring_rx_func contains the upper level (client) routine where the
* packets are destined and s_ring_rx_arg1/s_ring_rx_arg2 are the
* cookie meant for the client.
*/
/* ARGSUSED */
static void
{
void *arg1;
int cnt;
ringp->s_ring_tid = 0;
ringp->s_ring_count = 0;
ringp->s_ring_size = 0;
if (tid != 0) {
tid = 0;
}
/*
* If we have a soft ring set which is doing
* bandwidth control, we need to decrement its
* srs_size so it can have a accurate idea of
* what is the real data queued between SRS and
* its soft rings. We decrement the size for a
* packet only when it gets processed by both
* SRS and the soft ring.
*/
}
}
/*
* mac_soft_ring_worker
*
* The soft ring worker routine to process any queued packets. In
* normal case, the worker thread is bound to a CPU. It the soft
* ring is dealing with TCP packets, then the worker thread will
* be bound to the same CPU as the TCP squeue.
*/
static void
{
for (;;) {
}
/*
* Either we have work to do, or we have been asked to
* shutdown temporarily or permanently
*/
goto done;
}
done:
while (!(ringp->s_ring_state &
goto start;
}
}
thread_exit();
}
/*
* mac_soft_ring_intr_enable and mac_soft_ring_intr_disable
*
* these functions are called to toggle the sending of packets to the
* client. They are called by the client. the client gets the name
* of these routine and corresponding cookie (pointing to softring)
* during capability negotiation at setup time.
*
* Enabling is allow the processing thread to send packets to the
* client while disabling does the opposite.
*/
void
{
}
{
/*
* Stop worker thread from sending packets above.
* Squeue will poll soft ring when it needs packets.
*/
}
return (sring_blanked);
}
/*
* mac_soft_ring_poll
*
* This routine is called by the client to poll for packets from
* the soft ring. The function name and cookie corresponding to
* the soft ring is exchanged during capability negotiation during
* setup.
*/
mblk_t *
{
int cnt = 0;
return (NULL);
}
ringp->s_ring_count = 0;
ringp->s_ring_size = 0;
} else {
cnt++;
}
} else {
}
}
/*
* Update the shared count and size counters so
* that SRS has a accurate idea of queued packets.
*/
return (head);
}
/*
* mac_soft_ring_dls_bypass
*
* Enable direct client (IP) callback function from the softrings.
* Callers need to make sure they don't need any DLS layer processing
*/
void
{
}
/*
* mac_soft_ring_signal
*
* Typically used to set the soft ring state to QUIESCE, CONDEMNED, or
* RESTART.
*
* In the Rx side, the quiescing is done bottom up. After the Rx upcalls
* from the driver are done, then the Rx SRS is quiesced and only then can
* we signal the soft rings. Thus this function can't be called arbitrarily
* without satisfying the prerequisites. On the Tx side, the threads from
* top need to quiesced, then the Tx SRS and only then can we signal the
* Tx soft rings.
*/
void
{
}
/*
* mac_tx_soft_ring_drain
*
* The transmit side drain routine in case the soft ring was being
* used to transmit packets.
*/
static void
{
void *arg1;
void *arg2;
saved_pkt_count = saved_size = 0;
ringp->s_ring_count = 0;
ringp->s_ring_size = 0;
/* Device out of tx desc, set block */
ringp->s_ring_count +=
if (ringp->s_ring_tx_woken_up) {
} else {
}
return;
} else {
}
}
if (ringp->s_ring_state &
}
ringp->s_ring_state &=
if (wakeup_required) {
/*
* If the client is not the primary MAC client, then we
* need to send the notification to the clients upper
* MAC, i.e. mci_upper_mip.
*/
}
}
}