ipmgmt_persist.c revision ec3706caae60369bd59b4a7a2de365fc74637504
/*
* 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
*/
/*
*/
/*
* Contains DB walker functions, which are of type `db_wfunc_t';
*
* typedef boolean_t db_wfunc_t(void *cbarg, nvlist_t *db_nvl, char *buf,
* size_t bufsize, int *errp);
*
* ipadm_rw_db() walks through the data store, one line at a time and calls
* these call back functions with:
* `cbarg' - callback argument
* `db_nvl' - representing a line from DB in nvlist_t form
* `buf' - character buffer to hold modified line
* `bufsize'- size of the buffer
* `errp' - captures any error inside the walker function.
*
* All the 'write' callback functions modify `db_nvl' based on `cbarg' and
* copy string representation of `db_nvl' (using ipadm_nvlist2str()) into `buf'.
* To delete a line from the DB, buf[0] is set to `\0'. Inside ipadm_rw_db(),
* the modified `buf' is written back into DB.
*
* All the 'read' callback functions, retrieve the information from the DB, by
* reading `db_nvl' and then populate the `cbarg'.
*/
#include <stdlib.h>
#include <strings.h>
#include <errno.h>
#include <assert.h>
#include <unistd.h>
#include "ipmgmt_impl.h"
/*
* flag used by ipmgmt_persist_aobjmap() to indicate address type is
* IPADM_ADDR_IPV6_ADDRCONF.
*/
#define IPMGMT_ATYPE_V6ACONF 0x1
extern pthread_rwlock_t ipmgmt_dbconf_lock;
/*
* Checks if the database nvl, `db_nvl' contains and matches ALL of the passed
* in private nvpairs `proto', `ifname' & `aobjname'.
*/
static boolean_t
const char *aobjname)
{
char *db_aobjname = NULL;
char *name;
/* walk through db_nvl and retrieve all its private nvpairs */
}
/* no intersection - different protocols. */
return (B_FALSE);
}
/* no intersection - different interfaces. */
return (B_FALSE);
}
/* no intersection - different address objects */
return (B_FALSE);
}
return (B_TRUE);
}
/*
* Checks if the database nvl, `db_nvl' and the input nvl, `in_nvl' intersects.
*/
static boolean_t
{
char *name;
/* walk through in_nvl and retrieve all its private nvpairs */
}
}
/*
* Checks if the database nvl, `db_nvl', contains and matches ANY of the passed
* in private nvpairs `proto', `ifname' & `aobjname'.
*/
static boolean_t
{
char *db_aobjname = NULL;
char *name;
/* walk through db_nvl and retrieve all private nvpairs */
}
return (B_FALSE);
}
return (B_FALSE);
}
return (B_FALSE);
}
return (B_TRUE);
}
/*
* Retrieves the property value from the DB. The property whose value is to be
* retrieved is in `pargp->ia_pname'.
*/
/* ARGSUSED */
int *errp)
{
char *pval;
int err = 0;
*errp = 0;
return (B_TRUE);
&pval)) == 0) {
/*
* We have retrieved what we are looking for.
* Stop the walker.
*/
} else {
err = 0;
}
return (cont);
}
/*
* Removes the property value from the DB. The property whose value is to be
* removed is in `pargp->ia_pname'.
*/
/* ARGSUSED */
int *errp)
{
*errp = 0;
return (B_TRUE);
return (B_TRUE);
/*
* We found the property in the DB. If IPMGMT_REMOVE is not set then
* delete the entry from the db. If it is set, then the property is a
* multi-valued property so just remove the specified values from DB.
*/
char pval[MAXPROPVALLEN];
if (*errp != 0)
return (B_FALSE);
/*
* multi-valued properties are represented as comma separated
* values. Use string tokenizer functions to split them and
* search for the value to be removed.
*/
if (pval[0] != '\0')
}
}
} else {
else
buf[0] = '\0';
return (B_FALSE);
}
if (*errp != 0)
return (B_FALSE);
/* buffer overflow */
}
} else {
buf[0] = '\0';
}
/* stop the search */
return (B_FALSE);
}
/*
* Input arguments can have IPADM_NVP_AOBJNAME or IPADM_NVP_IFNAME. A match is
* found, when one of the following occurs first.
* - the input aobjname matches the db aobjname. Return the db address.
* - the input interface matches the db interface. Return all the
* matching db lines with addresses.
*/
/* ARGSUSED */
int *errp)
{
char *db_aobjname = NULL;
char name[IPMGMT_STRSIZE];
/* Parse db nvlist */
}
return (B_TRUE);
/* Check for a match between the aobjnames or the interface name */
} else {
}
if (add_nvl) {
if (*errp == 0)
}
return (B_TRUE);
}
/*
* This function takes the appropriate lock, read or write, based on the
* `db_op' and then calls DB walker ipadm_rw_db().
*/
extern int
{
int err;
if (writeop) {
(void) pthread_rwlock_wrlock(&ipmgmt_dbconf_lock);
} else {
(void) pthread_rwlock_rdlock(&ipmgmt_dbconf_lock);
mode = 0;
}
(void) pthread_rwlock_unlock(&ipmgmt_dbconf_lock);
return (err);
}
/*
* Used to add an entry towards the end of DB. It just returns B_TRUE for
* every line of the DB. When we reach the end, ipadm_rw_db() adds the
* line at the end.
*/
/* ARGSUSED */
{
return (B_TRUE);
}
/*
* This function is used to update or create an entry in DB. The nvlist_t,
* `in_nvl', represents the line we are looking for. Once we ensure the right
* line from DB, we update that entry.
*/
int *errp)
{
char pval[MAXPROPVALLEN];
return (B_TRUE);
break;
}
return (B_TRUE);
return (B_FALSE);
/*
* If IPMGMT_APPEND is set then we are dealing with multi-valued
* properties. We append to the entry from the db, with the new value.
*/
if (flags & IPMGMT_APPEND) {
&dbstrval)) != 0)
return (B_FALSE);
instrval);
return (B_FALSE);
} else {
/* case of in-line update of a db entry */
return (B_FALSE);
}
/* buffer overflow */
}
*errp = 0;
/* we updated the DB entry, so do not continue */
return (B_FALSE);
}
/*
* For the given `cbarg->cb_ifname' interface, retrieves any persistent
* interface information (used in 'ipadm show-if')
*/
/* ARGSUSED */
int *errp)
{
char *afstr;
*errp = 0;
return (B_TRUE);
}
break;
}
return (B_FALSE); /* don't continue the walk */
}
}
} else {
}
/* Terminate the walk if we found both v4 and v6 interfaces. */
return (B_FALSE);
return (B_TRUE);
}
/*
* Deletes those entries from the database for which interface name
* matches with the given `cbarg->cb_ifname'
*/
/* ARGSUSED */
int *errp)
{
char *afstr;
char *aobjname;
*errp = 0;
return (B_TRUE);
goto delete;
return (B_TRUE);
}
/* Reset all the interface configurations for 'ifname' */
goto delete;
}
if (!isv6 &&
goto delete;
}
/*
* This must be an address property. Delete this
* line if there is a match in the address family.
*/
goto delete;
}
}
/*
* If aobjfound = B_FALSE, then this address is not
* available in active configuration. We should go ahead
* and delete it.
*/
if (!aobjfound)
goto delete;
}
/*
* If we are removing both v4 and v6 interface, then we get rid of
* all the properties for that interface. On the other hand, if we
* are deleting only v4 instance of an interface, then we delete v4
* properties only.
*/
switch (proto) {
case MOD_PROTO_IPV6:
if (isv6)
goto delete;
break;
case MOD_PROTO_IPV4:
if (!isv6)
goto delete;
break;
case MOD_PROTO_IP:
/* this should never be the case, today */
assert(0);
break;
}
}
/* Not found a match yet. Continue processing the db */
return (B_TRUE);
/* delete the line from the db */
buf[0] = '\0';
return (B_TRUE);
}
/*
* Deletes those entries from the database for which address object name
* matches with the given `cbarg->cb_aobjname'
*/
/* ARGSUSED */
int *errp)
{
*errp = 0;
return (B_TRUE);
/* delete the line from the db */
buf[0] = '\0';
return (B_TRUE);
}
/*
* Retrieves all interface props, including addresses, for given interface(s).
* `invl' contains the list of interfaces, for which information need to be
* retrieved.
*/
/* ARGSUSED */
int *errp)
{
char *db_ifname;
*errp = 0;
char name[IPMGMT_STRSIZE];
char *pstr;
&pstr) == 0) {
if (proto == MOD_PROTO_IPV4)
else if (proto == MOD_PROTO_IPV6)
else
} else {
else
}
}
if (*errp == 0)
}
}
return (B_TRUE);
}
/*
* helper function for ipmgmt_aobjmap_op(). Adds the node pointed by `nodep'
* into `aobjmap' structure.
*/
static int
{
return (ENOMEM);
/* Add the node at the beginning of the list */
} else {
}
return (0);
}
/*
* A recursive function to generate alphabetized number given a decimal number.
* Decimal 0 to 25 maps to 'a' to 'z' and then the counting continues with 'aa',
* 'ab', 'ac', et al.
*/
static void
{
if (num >= 26)
(*cp)++;
}
}
/*
* This function generates an `aobjname', when required, and then does
* lookup-add. If `nodep->am_aobjname' is not an empty string, then it walks
* through the `aobjmap' to check if an address object with the same
* `nodep->am_aobjname' exists. If it exists, EEXIST is returned as duplicate
* `aobjname's are not allowed.
*
* If `nodep->am_aobjname' is an empty string then the daemon generates an
* `aobjname' using the `am_nextnum', which contains the next number to be
* used to generate `aobjname'. `am_nextnum' is converted to base26 using
* `a-z' alphabets in i_ipmgmt_num2priv_aobjname().
*
* `am_nextnum' will be 0 to begin with. Every time an address object that
* needs `aobjname' is added it's incremented by 1. So for the first address
* object on net0 the `am_aobjname' will be net0/_a and `am_nextnum' will be 1.
* For the second address object on that interface `am_aobjname' will be net0/_b
* and `am_nextnum' will incremented to 2.
*/
static int
{
break;
/*
* if `aobjname' is empty, then the daemon has to generate the
* next `aobjname' for the given interface and family.
*/
return (EINVAL);
cp[0] = '\0';
return (EINVAL);
}
} else {
return (EEXIST);
}
}
return (i_ipmgmt_add_amnode(nodep));
}
/*
* Performs following operations on the global `aobjmap' linked list.
* (a) ADDROBJ_ADD: add or update address object in `aobjmap'
* (b) ADDROBJ_DELETE: delete address object from `aobjmap'
* (c) ADDROBJ_LOOKUPADD: place a stub address object in `aobjmap'
* (d) ADDROBJ_SETLIFNUM: Sets the lifnum for an address object in `aobjmap'
*/
int
{
int err = 0;
switch (op) {
case ADDROBJ_ADD:
/*
* check for stub nodes (added by ADDROBJ_LOOKUPADD) and
* update, else add the new node.
*/
/*
* For IPv6, we need to distinguish between the
* linklocal and non-linklocal nodes
*/
nodep->am_aobjname) == 0 &&
break;
}
/* update the node */
}
} else {
break;
}
head->am_nextnum);
}
break;
case ADDROBJ_DELETE:
nodep->am_aobjname) == 0) {
/*
* There could be multiple IPV6_ADDRCONF nodes,
* with same address object name, so check for
* logical number also.
*/
break;
}
}
/*
* If the address object is in both active and
* persistent configuration and the user is deleting it
* only from active configuration then mark this node
* for deletion by reseting IPMGMT_ACTIVE bit.
* With this the same address object name cannot
* be reused until it is permanently removed.
*/
/* Update flags in the in-memory map. */
/* Update info in file. */
} else {
/* otherwise delete the node */
else
}
} else {
}
break;
case ADDROBJ_LOOKUPADD:
break;
case ADDROBJ_SETLIFNUM:
break;
}
nodep->am_aobjname) == 0) {
}
}
break;
/* update the lifnum */
} else {
}
break;
default:
assert(0);
}
return (err);
}
/*
* Given a node in `aobjmap', this function converts it into nvlist_t structure.
* The content to be written to DB must be represented as nvlist_t.
*/
static int
{
int err;
char strval[IPMGMT_STRSIZE];
goto fail;
np->am_aobjname)) != 0)
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
goto fail;
struct sockaddr_in6 *in6;
if (np->am_linklocal &&
"default")) != 0)
goto fail;
} else {
IPMGMT_STRSIZE) == NULL) {
goto fail;
}
strval)) != 0)
goto fail;
}
} else {
"")) != 0)
goto fail;
}
return (err);
fail:
nvlist_free(*nvl);
return (err);
}
/*
* Read the aobjmap data store and build the in-memory representation
* of the aobjmap. We don't need to hold any locks while building this as
* we do this in very early stage of daemon coming up, even before the door
* is opened.
*/
/* ARGSUSED */
extern boolean_t
int *errp)
{
struct sockaddr_in6 *in6;
*errp = 0;
return (B_TRUE);
sizeof (node.am_aobjname));
} else {
}
}
}
}
/* we have all the information we need, add the node */
return (B_TRUE);
}
/*
* Updates an entry from the temporary cache file, which matches the given
* address object name.
*/
/* ARGSUSED */
static boolean_t
{
*errp = 0;
return (B_TRUE);
if (flags & IPMGMT_ATYPE_V6ACONF) {
&db_lifnumstr) != 0 ||
&in_lifnumstr) != 0 ||
return (B_TRUE);
}
/* we found the match */
/* buffer overflow */
}
/* stop the walker */
return (B_FALSE);
}
/*
* Deletes an entry from the temporary cache file, which matches the given
* address object name.
*/
/* ARGSUSED */
static boolean_t
{
char *db_lifnumstr = NULL;
*errp = 0;
nodep->am_aobjname))
return (B_TRUE);
return (B_TRUE);
}
/* we found the match, delete the line from the db */
buf[0] = '\0';
/* stop the walker */
return (B_FALSE);
}
/*
* Adds or deletes aobjmap node information into a temporary cache file.
*/
extern int
{
int err;
if (op == IPADM_DB_WRITE) {
return (err);
else
} else {
}
return (err);
}