network_rcm.c revision f595a68a3b8953a12aa778c2abd7642df8da8c3a
/*
* 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 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* This RCM module adds support to the RCM framework for an abstract
* namespace for network devices (DLPI providers).
*/
#include <alloca.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <synch.h>
#include <libintl.h>
#include <errno.h>
#include <libdevinfo.h>
#include <libdlaggr.h>
#include "rcm_module.h"
/*
* Definitions
*/
#ifndef lint
#define _(x) gettext(x)
#else
#define _(x) x
#endif
/* operations */
#define NET_OFFLINE 1
#define NET_ONLINE 2
#define NET_REMOVE 3
#define NET_SUSPEND 4
#define NET_RESUME 5
typedef struct net_cache
{
char *resource;
char *exported;
char *driver;
int ppa;
int flags;
} net_cache_t;
static net_cache_t cache_head;
static net_cache_t cache_tail;
static mutex_t cache_lock;
/* module interface routines */
static int net_register(rcm_handle_t *);
static int net_unregister(rcm_handle_t *);
char **, nvlist_t *, rcm_info_t **);
uint_t, char **, rcm_info_t **);
rcm_info_t **);
rcm_info_t **);
rcm_info_t **);
rcm_info_t **);
/* module private routines */
static void free_cache(void);
static void free_node(net_cache_t *);
static void cache_insert(net_cache_t *);
/*
* Module-Private data
*/
static struct rcm_mod_ops net_ops = {
};
/*
* Module Interface Routines
*/
/*
* rcm_mod_init()
*
* Update registrations, and return the ops structure.
*/
struct rcm_mod_ops *
rcm_mod_init(void)
{
/* Return the ops vectors */
return (&net_ops);
}
/*
* rcm_mod_info()
*
* Return a string describing this module.
*/
const char *
rcm_mod_info(void)
{
return ("Network namespace module %I%");
}
/*
* rcm_mod_fini()
*
* Destroy the cache.
*/
int
rcm_mod_fini(void)
{
free_cache();
(void) mutex_destroy(&cache_lock);
return (RCM_SUCCESS);
}
/*
* net_register()
*
* Make sure the cache is properly sync'ed, and its registrations
* are in order.
*
* Locking: the cache is locked by update_cache, and is held
* throughout update_cache's execution because it reads and
* possibly modifies cache links continuously.
*/
static int
{
return (RCM_SUCCESS);
}
/*
* net_unregister()
*
* Manually walk through the cache, unregistering all the networks.
*
* Locking: the cache is locked throughout the execution of this routine
* because it reads and modifies cache links continuously.
*/
static int
{
/* Walk the cache, unregistering everything */
(void) mutex_lock(&cache_lock);
while (probe != &cache_tail) {
}
(void) mutex_unlock(&cache_lock);
return (RCM_SUCCESS);
}
/*
* Since all we do is pass operations thru, we provide a general
* routine for passing through operations.
*/
/*ARGSUSED*/
static int
{
char *exported;
int rv;
/*
* Lock the cache just long enough to extract information about this
* resource.
*/
(void) mutex_lock(&cache_lock);
if (!node) {
_("NET: unrecognized resource %s\n"), rsrc);
(void) mutex_unlock(&cache_lock);
return (RCM_SUCCESS);
}
/*
* Since node->exported could be freed after we drop cache_lock,
* allocate a stack-local copy. We don't use strdup() because some of
* the operations (such as NET_REMOVE) are not allowed to fail. Note
* that node->exported is never more than MAXPATHLEN bytes.
*/
/*
* Remove notifications are unconditional in the RCM state model,
* so it's safe to remove the node from the cache at this point.
* And we need to remove it so that we will recognize it as a new
* resource following the reattachment of the resource.
*/
if (op == NET_REMOVE) {
}
(void) mutex_unlock(&cache_lock);
switch (op) {
case NET_SUSPEND:
break;
case NET_OFFLINE:
/* device is aggregated */
"Resource is in use by aggregation"));
gettext("NET: malloc failure"));
}
return (RCM_FAILURE);
}
break;
case NET_ONLINE:
break;
case NET_REMOVE:
break;
case NET_RESUME:
break;
default:
return (RCM_FAILURE);
}
if (rv != RCM_SUCCESS) {
char format[256];
_("RCM operation on dependent %s did not succeed"),
exported);
}
return (rv);
}
/*
* net_offline()
*
* Determine dependents of the resource being offlined, and offline
* them all.
*/
static int
{
dependent_reason, NULL));
}
/*
* net_online()
*
* Online the previously offlined resource, and online its dependents.
*/
static int
{
dependent_reason, NULL));
}
/*
* net_getinfo()
*
* Gather usage information for this resource.
*
* Locking: the cache is locked while this routine looks up the
* resource and extracts copies of any piece of information it needs.
* The cache is then unlocked, and this routine performs the rest of
* its functions without touching any part of the cache.
*/
/*ARGSUSED*/
static int
{
int len;
char *exported;
char nic[64];
const char *info_fmt;
info_fmt = _("Network interface %s");
(void) mutex_lock(&cache_lock);
if (!node) {
_("NET: unrecognized resource %s\n"), rsrc);
(void) mutex_unlock(&cache_lock);
return (RCM_FAILURE);
}
if (!exported) {
(void) mutex_unlock(&cache_lock);
return (RCM_FAILURE);
}
(void) mutex_unlock(&cache_lock);
return (RCM_FAILURE);
}
/* Fill in the string */
/* Get dependent info if requested */
}
&exported, 1);
return (RCM_SUCCESS);
}
/*
* net_suspend()
*
* Notify all dependents that the resource is being suspended.
* Since no real operation is involved, QUERY or not doesn't matter.
*
* Locking: the cache is only used to retrieve some information about
* this resource, so it is only locked during that retrieval.
*/
static int
{
dependent_reason, (void *)interval));
}
/*
* net_resume()
*
* Resume all the dependents of a suspended network.
*
* Locking: the cache is only used to retrieve some information about
* this resource, so it is only locked during that retrieval.
*/
static int
{
NULL));
}
/*
* net_remove()
*
* This is another NO-OP for us, we just passthru the information. We
* don't need to remove it from our cache. We don't unregister
* interest at this point either; the network device name is still
* around. This way we don't have to change this logic when we
* gain the ability to learn about DR attach operations.
*/
static int
{
NULL));
}
/*
* Cache management routines. Note that the cache is implemented as a
* trivial linked list, and is only required because RCM doesn't
* provide enough state about our own registrations back to us. This
* linked list implementation probably clobbers the CPU cache pretty
* well.
*/
/*
* cache_lookup()
*
* Get a cache node for a resource. Call with cache lock held.
*/
static net_cache_t *
cache_lookup(const char *resource)
{
while (probe != &cache_tail) {
return (probe);
}
}
return (NULL);
}
/*
* free_node()
*
* Free a node. Make sure it isn't in the list!
*/
static void
{
if (node) {
}
}
/*
* cache_insert()
*
* Call with the cache_lock held.
*/
static void
{
/* insert at the head for best performance */
}
/*
* cache_remove()
*
* Call with the cache_lock held.
*/
static void
{
}
/*
* devfs_entry()
*
* Call with the cache_lock held.
*/
/*ARGSUSED*/
static int
{
char *devfspath;
char resource[MAXPATHLEN];
char *name;
char *cp;
int instance;
/* doesn't look like a network device */
return (DI_WALK_CONTINUE);
}
/* what else can we do? */
return (DI_WALK_CONTINUE);
}
if (!devfspath) {
/* no devfs path?!? */
return (DI_WALK_CONTINUE);
}
/* ignore pseudo devices, probably not really NICs */
return (DI_WALK_CONTINUE);
}
resource);
} else {
resource);
if (!probe) {
return (DI_WALK_CONTINUE);
}
return (DI_WALK_CONTINUE);
}
}
return (DI_WALK_CONTINUE);
}
/*
* update_cache()
*
* The devinfo tree walking code is lifted from ifconfig.c.
*/
static void
{
int rv;
(void) mutex_lock(&cache_lock);
/* first we walk the entire cache, marking each entry stale */
while (probe != &cache_tail) {
}
if (root == DI_NODE_NIL) {
goto done;
}
while (probe != &cache_tail) {
continue;
}
continue;
}
if (rv != RCM_SUCCESS) {
_("NET: failed to register %s\n"),
} else {
"NET: registered %s (as %s)\n",
}
}
done:
(void) mutex_unlock(&cache_lock);
}
/*
* free_cache()
*/
static void
free_cache(void)
{
(void) mutex_lock(&cache_lock);
while (probe != &cache_tail) {
}
(void) mutex_unlock(&cache_lock);
}
/*
* is_aggregated() checks whether a NIC being removed is part of an
* aggregation.
*/
typedef struct aggr_walker_state_s {
static int
{
int i;
continue;
/* found matching MAC port */
}
return (0);
}
static boolean_t
{
return (B_FALSE);
}
}