libdlflow.c revision 25ec3e3dd27cc1038c10efa18ed08f064eab5fbe
/*
* 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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <stdio.h>
#include <sys/ethernet.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <stropts.h>
#include <stdlib.h>
#include <errno.h>
#include <strings.h>
#include <libintl.h>
#include <netdb.h>
#include <net/if_types.h>
#include <libdlflow.h>
#include <libdlflow_impl.h>
#include <libdladm_impl.h>
/* minimum buffer size for DLDIOCWALKFLOW */
#define DLADM_FLOW_DB "/etc/dladm/flowadm.conf"
#define DLADM_FLOW_DB_TMP "/etc/dladm/flowadm.conf.new"
#define DLADM_FLOW_DB_LOCK "/tmp/flowadm.conf.lock"
#define DLADM_FLOW_DB_OWNER UID_DLADM
#define DLADM_FLOW_DB_GROUP GID_SYS
#define MAXLINELEN 1024
#define MAXPATHLEN 1024
/* database file parameters */
static const char *BW_LIMIT = "bw_limit";
static const char *PRIORITY = "priority";
static const char *LOCAL_IP_ADDR = "local_ip";
static const char *REMOTE_IP_ADDR = "remote_ip";
static const char *TRANSPORT = "transport";
static const char *LOCAL_PORT = "local_port";
static const char *REMOTE_PORT = "remote_port";
static const char *DSFIELD = "dsfield";
/*
* Open and lock the flowadm configuration file lock. The lock is
* acquired as a reader (F_RDLCK) or writer (F_WRLCK).
*/
static int
i_dladm_flow_lock_db(short type)
{
int lock_fd;
DLADM_FLOW_DB_PERMS)) < 0)
return (-1);
(void) unlink(DLADM_FLOW_DB_LOCK);
return (-1);
}
return (lock_fd);
}
/*
* Unlock and close the specified file.
*/
static void
i_dladm_flow_unlock_db(int fd)
{
if (fd < 0)
return;
(void) unlink(DLADM_FLOW_DB_LOCK);
}
/*
* Parse one line of the link flowadm DB
* Returns -1 on failure, 0 on success.
*/
{
char *token;
/* flow name */
goto done;
goto done;
/* resource control and flow descriptor parameters */
goto done;
goto done;
goto done;
if (status != DLADM_STATUS_OK)
goto done;
&attr->fi_flow_desc);
if (status != DLADM_STATUS_OK)
goto done;
&attr->fi_flow_desc);
if (status != DLADM_STATUS_OK)
goto done;
&attr->fi_flow_desc);
if (status != DLADM_STATUS_OK)
goto done;
}
}
done:
return (status);
}
/*
* Write the attribute of a group to the specified file. Returns 0 on
* success, -1 on failure.
*/
static int
{
/* flow policy */
/* flow descriptor */
int prefix_len, prefix_max;
} else {
}
(void) dladm_mask2prefixlen(
&prefix_len);
ap, prefix_len));
}
int prefix_len, prefix_max;
} else {
}
(void) dladm_mask2prefixlen(
&prefix_len);
ap, prefix_len));
}
return (0);
}
static dladm_status_t
void *arg,
const char *root)
{
char line[MAXLINELEN];
char *db_file, *tmp_db_file;
char db_file_buf[MAXPATHLEN];
char tmp_db_file_buf[MAXPATHLEN];
} else {
}
return (DLADM_STATUS_FLOW_DB_ERR);
return (DLADM_STATUS_FLOW_DB_OPEN_ERR);
}
DLADM_FLOW_DB_PERMS)) == -1) {
return (DLADM_STATUS_FLOW_DB_OPEN_ERR);
}
(void) unlink(tmp_db_file);
return (DLADM_STATUS_FLOW_DB_OPEN_ERR);
}
/* skip comments */
if (BLANK_LINE(line)) {
goto failed;
continue;
}
goto failed;
switch (fn_rc) {
case -1:
/* failure, stop walking */
goto failed;
case 0:
/*
* Success, write group attributes, which could
* have been modified by fn().
*/
goto failed;
break;
case 1:
/* skip current group */
break;
}
}
goto failed;
goto failed;
goto failed;
(void) unlink(tmp_db_file);
return (DLADM_STATUS_FLOW_DB_ERR);
}
return (DLADM_STATUS_OK);
(void) unlink(tmp_db_file);
return (status);
}
/*
* Remove existing flow from DB.
*/
typedef struct remove_db_state {
static int
{
return (0);
else {
sizeof (dld_flowinfo_t));
return (1);
}
}
/* ARGSUSED */
static int
{
!= 0)
return (-1);
return (-1);
}
return (0);
}
/*
* Create a flow in the DB.
*/
typedef struct modify_db_state {
static dladm_status_t
{
char line[MAXLINELEN];
char *db_file;
char db_file_buf[MAXPATHLEN];
int lock_fd;
} else {
}
return (DLADM_STATUS_FLOW_DB_ERR);
return (DLADM_STATUS_FLOW_DB_OPEN_ERR);
}
/* look for existing group with same flowname */
/* skip comments */
if (BLANK_LINE(line))
continue;
/* ignore corrupted lines */
continue;
/* flow id */
/* group with flow id already exists */
goto failed;
}
}
/*
* If we get here, we've verified that no existing group with
* the same flow id already exists. Its now time to add the new
* group to the DB.
*/
return (status);
}
static dladm_status_t
{
/* create flow */
sizeof (mac_resource_props_t));
}
return (dladm_errno2status(errno));
return (DLADM_STATUS_OK);
}
static dladm_status_t
{
return (status);
}
/* ARGSUSED */
{
/* Extract flow attributes from attrlist */
&flowdesc)) != DLADM_STATUS_OK) {
return (status);
}
/* Extract resource_ctl and cpu_list from proplist */
&mrp)) != DLADM_STATUS_OK) {
return (status);
}
/* Add flow in kernel */
if (status != DLADM_STATUS_OK)
return (status);
/* Add flow to DB */
if (!tempop) {
sizeof (db_attr.fi_flowname));
return (status);
}
/* set flow properties */
proplist);
if (status != DLADM_STATUS_OK) {
return (status);
}
}
}
return (status);
}
/*
* Remove a flow.
*/
/* ARGSUSED */
const char *root)
{
/* remove flow */
if ((status != DLADM_STATUS_OK) &&
goto done;
/* remove flow from DB */
if (!tempop) {
/* flow DB */
s = dladm_errno2status(errno);
goto done;
}
/* flow prop DB */
}
done:
if (!tempop) {
if (s == DLADM_STATUS_OK) {
if (status == DLADM_STATUS_NOTFOUND)
status = s;
} else {
if (s != DLADM_STATUS_NOTFOUND)
status = s;
}
}
return (status);
}
/*
* Get an existing flow in the DB.
*/
typedef struct get_db_state {
void *gs_arg;
/*
* For each flow which matches the linkid, copy all flow information
* to a new dladm_flow_attr_t structure and call the provided
* function. This is used to display perisistent flows from
* the database.
*/
static int
{
sizeof (attr.fa_flowname));
sizeof (attr.fa_flow_desc));
sizeof (attr.fa_resource_props));
}
return (0);
}
/*
* Walk through the flows defined on the system and for each flow
* invoke <fn>(<arg>, <flow>);
* Currently used for show-flow.
*/
/* ARGSUSED */
{
int i, bufsize;
return (DLADM_STATUS_BADARG);
if (persist) {
if (status != DLADM_STATUS_OK)
return (status);
} else {
return (status);
}
bufsize *= 2;
continue;
}
}
goto bail;
}
sizeof (attr.fa_flowname));
sizeof (attr.fa_flow_desc));
sizeof (attr.fa_resource_props));
break;
}
}
bail:
return (status);
}
{
char name[MAXFLOWNAMELEN];
char line[MAXLINELEN];
return (DLADM_STATUS_DB_NOTFOUND);
/* skip comments */
if (BLANK_LINE(line))
continue;
if (s != DLADM_STATUS_OK) {
status = s;
continue;
}
sizeof (attr.fi_flowname));
if (s != DLADM_STATUS_OK)
status = s;
}
if (s != DLADM_STATUS_OK)
status = s;
return (status);
}
{
return (DLADM_STATUS_BADARG);
while (prefixlen > 0) {
if (prefixlen >= 8) {
*mask++ = 0xFF;
prefixlen -= 8;
continue;
}
prefixlen--;
}
return (DLADM_STATUS_OK);
}
{
int bits;
int i, end;
switch (plen) {
case IP_ABITS:
end = 3;
break;
case IPV6_ABITS:
end = 0;
break;
default:
return (DLADM_STATUS_BADARG);
}
for (i = 3; i >= end; i--) {
plen -= 32;
continue;
}
if (bits == 0)
break;
}
return (DLADM_STATUS_OK);
}