filters.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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 2002-2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <ipp/ipp_config.h>
/* Implementation for filter management and configuration support of ipgpc */
/* Globals */
/* max number of allowable filters */
/* max number of allowable classes */
/* Statics */
static int global_statinit(void);
static int initialize_tries(void);
static void initialize_tables(void);
static void initialize_ba_tables(void);
static void element_node_ref(element_node_t *);
static void element_node_unref(element_node_t *);
static int element_node_cache_constructor(void *, void *, int);
static int filter_name2id(unsigned *, char[], int32_t, int);
static int class_name2id(unsigned *, char[], int);
static void common_addfilter(fid_t *, int);
static void v4_addfilter(fid_t *, int);
static void v6_addfilter(fid_t *, int);
static void reset_dontcare_stats(void);
static int class_statinit(ipgpc_class_t *, int);
static int insertcid(ipgpc_class_t *, int *);
static void common_removefilter(int, fid_t *);
static void v4_removefilter(int, fid_t *);
static void v6_removefilter(int, fid_t *);
static void removecid(int);
static void remove_from_cid_filter_list(int, int);
static void removeclasses(ipp_flags_t);
static void freetriev6nodes(node_t **);
static int update_class_stats(ipp_stat_t *, void *, int);
static int update_global_stats(ipp_stat_t *, void *, int);
/*
* Module initialization code
*/
/*
* global_statinit()
*
* initializes global stats for ipgpc action module.
* global include:
* - number of filters loaded
* - number of classes loaded
* - number of packets that have passed through ipgpc since action create
* - number of bytes that have passed through ipgpc since action create
* if ipp_stat_create fails, an error code is returned
* if ipp_stat_named_init fails, an error code is returned
* 0 is returned on success
*/
static int
global_statinit(void)
{
int rc;
/* create stat structure */
ipgpc0dbg(("global_statinit: error creating ipp_stat entry"));
return (rc);
}
/* add stat name entries */
return (rc);
}
return (rc);
}
return (rc);
}
return (rc);
}
return (rc);
}
return (0);
}
static void
{
}
static int
initialize_tries(void)
{
/* IPv4 Source Address field structure */
return (ENOMEM);
}
/* IPv4 Destination Address field structure */
return (ENOMEM);
}
/* TCP Source Port field structure */
return (ENOMEM);
}
/* TCP Destination Port field structure */
return (ENOMEM);
}
/* IPv6 Source Address field structure */
return (ENOMEM);
}
/* IPv6 Destination Address field structure */
return (ENOMEM);
}
return (0);
}
static void
{
}
static void
initialize_tables(void)
{
/* Protocol selector structure */
/* UID selector structure */
UID_MASK);
/* PROJID selector structure */
/* IF_INDEX selector structure */
IF_MASK);
/* IF_GRPNM_INDEX selector structure */
/* DIR selector structure */
DIR_MASK);
}
static void
initialize_ba_tables(void)
{
}
static void
{
}
static void
{
}
}
/* ARGSUSED1 */
static int
{
return (0);
}
/* prime values to be used for hashing of filter and class tables */
1009, 1531, 2003, 2503, 3067, 3511, 4001, 5003, 6143, \
10007, 12281, 15013, 20011, 24571, 49139, 98299, \
100003, 196597, 393209, 786431, 1000003, 1251409, \
1572853, 3145721, 0}
/*
* ipgpc_initialize(in_aid)
*
* initializes locks, data structures, configuration variables used and
* sets globals. Will fail on memory or initialization error.
*/
int
{
int i;
int rc;
int sizes[] = IPGPC_PRIMES();
/* initialize globals */
ipgpc_num_fltrs = 0;
ipgpc_num_cls = 0;
ipgpc_npackets = 0;
ipgpc_nbytes = 0;
ipgpc_epackets = 0;
if (ipgpc_max_filters > 0) {
/* start with a reasonably small value to find closest prime */
if (sizes[i] >= ipgpc_max_filters) {
break;
}
}
if (sizes[i] == 0) {
ipgpc0dbg(("ipgpc_initialize: ipgpc_max_filters " \
"out of range"));
/* use the largest allowable value */
} else {
ipgpc_max_num_filters = sizes[i];
}
}
if (ipgpc_max_classes > 0) {
/* start with a reasonably small value to find closest prime */
if (sizes[i] >= ipgpc_max_classes) {
break;
}
}
if (sizes[i] == 0) {
ipgpc0dbg(("ipgpc_initialize: ipgpc_max_classes " \
"out of range"));
/* use the largest allowable value */
} else {
ipgpc_max_num_classes = sizes[i];
}
}
/* create filter id list */
if (ipgpc_fid_list == NULL) {
ipgpc0dbg(("ipgpc_initialize: failed to create fid list"));
return (ENOMEM);
}
/* create class id list */
if (ipgpc_cid_list == NULL) {
ipgpc0dbg(("ipgpc_initialize: failed to create cid list"));
return (ENOMEM);
}
/* create object caches */
sizeof (element_node_t), 0, element_node_cache_constructor,
/* initialize tries, catch memory errors */
if ((rc = initialize_tries()) != 0) {
return (rc);
}
initialize_tables(); /* no memory is allocated here */
initialize_ba_tables(); /* no memory is allocated here */
ipgpc0dbg(("ipgpc_initialize: global_statinit error " \
"%d", rc));
return (rc);
}
/* create default class */
/* add default class and record default class id */
ipgpc0dbg(("ipgpc_initialize: insert of default class failed" \
" with error %d", rc));
return (rc);
}
return (0);
}
/*
* Module modify code
*/
/*
* name_hash(name, M)
*
* hash function for a string (name) of lenght M
*/
unsigned
{
unsigned h;
h = ((64 * h) + *name);
}
return ((h % M));
}
/*
* ipgpc_filter_destructor(filter)
*
* frees any allocated memory pointed to in the filter structure
* this function should be run before freeing an ipgpc_filter_t
*/
void
{
}
}
}
}
/*
* filter_name2id(*out_id, name, filter_instance, in_num_filters)
*
* looks up name and instance in filter id table
* checks in_num_filters against max filter boundary
* if found, returns EEXIST and places the id in out_id
* if not found, returns ENOENT and places the new id in out_id
* if no additional filter ids are available, ENOMEM is returned
*/
static int
int in_num_filters)
{
unsigned h;
if (in_num_filters >= ipgpc_max_num_filters) {
return (ENOSPC); /* will exceed maximum number of filters */
}
/*
* search until fid w/ matching name is found or clean space is found
* if clean space is found, return first dirty space found or if
* none werer found, return clean space
*/
while ((ipgpc_fid_list[h].info != 0) &&
dirty = h;
}
}
h = (h + 1) % ipgpc_max_num_filters;
}
/*
* check to see if searching stopped because a clean spot was found
* and a dirty space was seen before
*/
return (ENOENT); /* name does not exist in table */
} else if (ipgpc_fid_list[h].info == 0) {
*out_id = h;
return (ENOENT); /* name does not exist in table */
} else {
*out_id = h;
return (ENOENT);
} else {
return (EEXIST); /* name exists in table */
}
}
}
/*
* class_name2id(*out_id, name, in_num_classes)
*
* looks up name in class id table
* checks in_num_classes against max class boundry
* if found, returns EEXIST and places the id in out_id
* if not found, returns ENOENT and places the new id in out_id
* if no additional class ids are available, ENOSPC is returned
*/
static int
{
unsigned h;
if (in_num_classes >= ipgpc_max_num_classes) {
return (ENOSPC); /* will exceed maximum number of classes */
}
/*
* search until cid w/ matching name is found or clean space is found
* if clean space is found, return first dirty space found or if
* none were found, return clean space
*/
while ((ipgpc_cid_list[h].info != 0) &&
dirty = h;
}
}
h = (h + 1) % ipgpc_max_num_classes;
}
/*
* check to see if searching stopped because a clean spot was found
* and a dirty space was seen before
*/
return (ENOENT); /* name does not exist in table */
} else if (ipgpc_cid_list[h].info == 0) {
*out_id = h;
return (ENOENT); /* name does not exist in table */
} else {
*out_id = h;
return (ENOENT); /* name does not exist in table */
} else {
return (EEXIST); /* name exists in table */
}
}
}
/*
* ipgpc_parse_filter(filter, nvlp)
*
* given a name value pair list, a filter structure is parsed. A valid
* filter must have a filter_name and originator id. Any value that is not
* present, will be given the default wildcard value for that selector
*/
int
{
char *s;
int i;
/* parse filter name */
return (EINVAL); /* filter name is missing, error */
}
/* parse originator */
&filter->originator) != 0) {
ipgpc0dbg(("ipgpc_parse_filter: originator missing"));
return (EINVAL);
}
/* check for max name length */
ipgpc0dbg(("ipgpc_parse_filter: filter name length > " \
"MAXNAMELEN"));
return (EINVAL);
}
/* parse interface group name */
} else {
/* check max interface group name lenght */
ipgpc0dbg(("ipgpc_parse_filter: interface group name" \
" > LIFNAMSIZ"));
return (EINVAL);
}
}
/* parse uid */
}
/* parse projid */
}
/* parse if_index */
!= 0) {
}
/* parse direction */
}
/* parse proto */
}
/*
* parse dsfield mask, if mask is present and dsfield value is not,
* then this is an invalid filter configuration
*/
== 0) {
/* parse dsfield */
!= 0) {
ipgpc0dbg(("ipgpc_parse_filter: dsfield missing" \
" when dsfield_mask 0x%x is present",
filter->dsfield_mask));
return (EINVAL);
}
} else {
filter->dsfield_mask = 0;
/* check to see if user added dsfield, but not dsfield_mask */
== 0) {
ipgpc0dbg(("ipgpc_parse_filter: dsfield_mask missing" \
" when dsfield 0x%x is present",
return (EINVAL);
}
}
/* parse source port */
}
/*
* parse source port mask, mask and value must be present, or neither
*/
!= 0) {
ipgpc0dbg(("ipgpc_parse_filter: sport_mask missing " \
return (EINVAL);
}
filter->sport_mask = 0;
} else { /* sport mask is present */
ipgpc0dbg(("ipgpc_parse_filter: sport missing " \
"when sport_mask %u is present",
filter->sport_mask));
return (EINVAL);
}
}
/* check for non-continuous mask */
ipgpc0dbg(("ipgpc_parse_filter: sport_mask is " \
"non-continuous"));
return (EINVAL);
}
/* parse destination port */
}
/*
* parse destination port mask, mask and value must be present,
* or neither
*/
!= 0) {
ipgpc0dbg(("ipgpc_parse_filter: dport_mask missing " \
return (EINVAL);
}
filter->dport_mask = 0;
} else { /* dport mask is present */
ipgpc0dbg(("ipgpc_parse_filter: dport missing " \
"when dport_mask %u is present",
filter->dport_mask));
return (EINVAL);
}
}
/* check for non-continuous mask */
ipgpc0dbg(("ipgpc_parse_filter: dport_mask is " \
"non-continuous"));
return (EINVAL);
}
/* parse precedence */
!= 0) {
}
/* parse priority */
!= 0) {
}
/* parse filter type */
!= 0) {
}
/* parse filter instance */
&filter->filter_instance) != 0) {
}
/* parse filter private field */
} else {
}
/*
* parse source address mask, if address is present, mask must be
* present
*/
!= 0) {
/* check if source address is present */
&nelem) == 0) {
ipgpc0dbg(("ipgpc_parse_filter: source address mask " \
"missing"));
return (EINVAL);
} else { /* both saddr and saddr_mask absent */
}
} else { /* saddr_mask present */
/* parse source address */
&nelem) != 0) {
ipgpc0dbg(("ipgpc_parse_filter: source address " \
"missing"));
return (EINVAL);
} else { /* saddr present */
}
}
/* check for non-continuous mask */
for (i = 0; i < 4; ++i) {
zero_found = B_TRUE;
} else {
if (zero_found) {
ipgpc0dbg(("ipgpc_parse_filter: "
"saddr_mask is non-continuous"));
return (EINVAL);
}
}
IP_ABITS)) {
ipgpc0dbg(("ipgpc_parse_filter: saddr_mask " \
"is non-continuous"));
return (EINVAL);
}
}
} else { /* IPGPC_V4_FLTR */
IP_ABITS)) {
ipgpc0dbg(("ipgpc_parse_filter: saddr_mask is " \
"non-continuous"));
return (EINVAL);
}
}
/* parse source address hostname */
} else {
}
/*
* parse destination address mask, if address is present, mask must be
* present
*/
!= 0) {
/* check if destination address is present */
&nelem) == 0) {
ipgpc0dbg(("ipgpc_parse_filter: destination address " \
"mask missing"));
return (EINVAL);
} else { /* both daddr and daddr_mask absent */
}
} else { /* daddr_mask present */
/* parse destination address */
&nelem) != 0) {
ipgpc0dbg(("ipgpc_parse_filter: destination address " \
"missing"));
return (EINVAL);
} else { /* daddr present */
}
}
/* check for non-continuous mask */
for (i = 0; i < 4; ++i) {
zero_found = B_TRUE;
} else {
if (zero_found) {
ipgpc0dbg(("ipgpc_parse_filter: "
"daddr_mask is non-continuous"));
return (EINVAL);
}
}
IP_ABITS)) {
ipgpc0dbg(("ipgpc_parse_filter: daddr_mask " \
"is non-continuous"));
return (EINVAL);
}
}
} else { /* IPGPC_V4_FLTR */
IP_ABITS)) {
ipgpc0dbg(("ipgpc_parse_filter: daddr_mask is " \
"non-continuous"));
return (EINVAL);
}
}
/* parse destination address hostname */
} else {
}
return (0);
}
/*
* iscontinuousmask(mask, len)
*
* Searches a given mask of length len from MSB to LSB looking for a zero
* bit followed by one bit. A continuous mask must be a string of zero or
* more ones followed by a string of zero or more zeros, which would return
* B_TRUE. Otherwise, it is not continuous and this function returns B_FALSE.
*/
static boolean_t
{
zero_found = B_TRUE;
} else {
if (zero_found) {
return (B_FALSE);
}
}
}
return (B_TRUE);
}
/*
* insertfid(filter_id, filter, class_id)
*
* creates a filter id (fid) structure for filter with filter_id.
* filter is associated with the input class id
* it is assumed that a fid will not be inserted for a filter that already
* exists by the same name.
*/
static void
{
ipgpc3dbg(("insert_fid: adding filter %s to class %s",
}
static void
{
int if_grpnm_hv;
/* start trie inserts */
/* add source port selector */
}
/* add destination port selector */
}
/* end trie inserts */
/* add diffserv field selector */
}
/* start table inserts */
/* add protocol selector */
}
/* add UID selector */
== NORMAL_VALUE) {
}
/* add PROJID selector */
}
/* add interface index selector */
}
/* add interface groupname selector */
} else {
}
== NORMAL_VALUE) {
}
/* add direction selector */
}
/* end table inserts */
}
static void
{
/* add IPv4 source address selector */
}
/* add IPv4 destination address selector */
}
}
static void
{
/* add IPv6 source address selector */
}
/* add IPv6 destination address selector */
}
}
/*
* ipgpc_addfilter(filter, class_name, flags)
*
* add the specified filter and associate it with the specified class
* name
* - add filter id to filter list
* - add filter keys to selector structures
* - ENOENT is returned if class does not exist
* - EEXIST is returned if add failed because filter name exists
* - ENOMEM is returned if no memory is available to add a new filter
* - EINVAL if filter.filter_type is invalid
* - 0 is returned on success
* flags is unused currently
*/
/* ARGSUSED1 */
int
{
unsigned filter_id;
int err = 0;
unsigned class_id;
EEXIST) {
return (err);
}
/* make sure filter does not already exist */
ipgpc0dbg(("ipgpc_addfilter: filter name %s already exists",
filter->filter_name));
return (err);
ipgpc0dbg(("ipgpc_addfilter: can not add filter %s, " \
"ipgpc_max_num_filteres has been reached",
filter->filter_name));
return (err);
}
/* add filter id to selector structures */
case IPGPC_GENERIC_FLTR:
/* add filter id to all selectors */
break;
case IPGPC_V4_FLTR:
/* add filter to common and V4 selectors */
break;
case IPGPC_V6_FLTR:
/* add filter to common and V6 selectors */
break;
default:
ipgpc0dbg(("ipgpc_addfilter(): invalid filter type %d",
return (EINVAL);
}
/* check to see if this is a catch all filter, which we reject */
if (fid->insert_map == 0) {
ipgpc0dbg(("ipgpc_addfilter(): filter %s rejected because " \
"catch all filters are not supported\n",
filter->filter_name));
/* cleanup what we allocated */
/* remove filter from filter list */
reset_dontcare_stats(); /* need to fixup stats */
return (EINVAL);
} else { /* associate filter with class */
}
return (0);
}
/*
* reset_dontcare_stats()
*
* when an insertion fails because zero selectors are specified in a filter
* the number of dontcare's recorded for each selector structure needs to be
* decremented
*/
static void
reset_dontcare_stats(void)
{
int i;
for (i = 0; i < NUM_TRIES; ++i) {
}
for (i = 0; i < NUM_TABLES; ++i) {
}
}
/*
* ipgpc_parse_class(out_class, nvlp)
*
* Given a name value pair list, a class structure will be parsed.
* To be a valid class, the class name, originator id and next action name
* must be present. gather_stats is optional, if absent default value is used
*/
int
{
char *name;
/* parse class name */
return (EINVAL); /* class name missing, error */
}
/* check for max name length */
ipgpc0dbg(("ipgpc_parse_class: class name length > " \
"MAXNAMELEN"));
return (EINVAL);
}
/* parse originator */
&out_class->originator) != 0) {
ipgpc0dbg(("ipgpc_parse_class: originator missing"));
return (EINVAL);
}
/* parse action name */
return (EINVAL); /* action name missing, error */
}
== IPP_ACTION_INVAL) {
return (EINVAL);
}
/* parse gather stats boolean */
&gather_stats) != 0) {
/* stats turned off by default */
} else {
}
return (0);
}
/*
* ipgpc_addclass(in_class, flags)
*
* adds the given class to the class id list.
* - EEXIST is returned if class of same name already exists
* - ENOSPC if there is no more available memory to add class
* - 0 for success
* flags is currently unused
*/
/* ARGSUSED */
int
int class_id;
int err;
ipgpc0dbg(("ipgpc_addclass: class name %s already exists",
in_class->class_name));
return (err);
ipgpc0dbg(("ipgpc_addclass: can not add class %s, " \
"ipgpc_max_num_classes has been reached",
in_class->class_name));
return (err);
}
/* add reference to next action */
/*
* the action id we want to reference must have been
* destroyed before we could reference it. remove class
* and fail.
*/
return (err);
}
return (0);
}
/*
* class_statinit(in_class, in_class_id)
*
* for the given class, create stats entries to record
* - next action id
* - number of bytes that matched this class
* - number of packets that matched this class
* - time in hrtime of last match for this class
* any failures are returned, zero on sucess
*/
static int
{
int rc;
/* create stat structure */
&ipp_cl_stats)) != 0) {
ipgpc0dbg(("class_statinit: error creating ipp_stat entry"));
return (rc);
}
/* create stats entry */
sizeof (ipgpc_class_stats_t));
/* set next action id */
return (rc);
}
return (rc);
}
return (rc);
}
/* make reference to kstat structure, for removal */
return (0);
}
/*
* insertcid(in_class, out_class_id)
*
* creates a class id (cid) structure for in_class, if in_class name
* does not exist already. id is associated with in_class. the internal
* id of the cid associated with in_class is returned in out_class_id
* - ENOENT is returned if in_class->class_name does not already exist
* - EEXIST is returned if in_class->class_name does already exist
* - ENOSPC is returned if by adding this class, the ipgpc_max_num_classes
* will be exceeded.
*/
static int
{
unsigned class_id;
/* see if entry already exists for class */
/* create new filter list for new class */
/* init kstat entry */
ipgpc0dbg(("insertcid: " \
"class_statinit failed with " \
"error %d", rc));
return (rc);
}
} else {
}
ipgpc3dbg(("insertcid: adding class %s",
in_class->class_name));
} else {
return (err);
}
*out_class_id = class_id;
return (err);
}
/*
* common_removefilter(in_filter_id, fid)
*
* removes in_filter_id from each of the common selector structures
*/
static void
{
int if_grpnm_hv;
/* start trie removes */
/* remove id from destination port trie */
/* end trie revmoves */
/* remove id from DiffServ field ba table */
/* start table removes */
/* remove id from protocol table */
/* remove id from UID table */
/* remove id from PROJID table */
/* remove id from interface id table */
/* remove id from interface group name table */
} else {
}
/* remove id from direction table */
/* end table removes */
}
/*
* v4_removefilter(in_filter_id, fid)
*
* removes id from IPV4 specific structures
*/
static void
{
/* remove id from source address trie */
/* remove id from destination address trie */
}
/*
* v6_removefilter(in_filter_id, fid)
*
* removes id from IPV6 specific structures
*/
static void
{
/* remove id from source address trie */
/* remove id from destination address trie */
}
/*
* ipgpc_removefilter(filter_name, filter_instance, flags)
*
* remove the filter associated with the specified name and instance
* - remove filter keys from all search tries
* - remove from filter id list
* - ENOENT is returned if filter name does not exist
* - returns 0 on success
*/
/* ARGSUSED */
int
{
unsigned filter_id;
int rc;
/* check to see if any filters are loaded */
if (ipgpc_num_fltrs == 0) {
return (ENOENT);
}
/* lookup filter name, only existing filters can be removed */
ipgpc_num_fltrs)) != EEXIST) {
return (rc);
}
case IPGPC_GENERIC_FLTR:
break;
case IPGPC_V4_FLTR:
break;
case IPGPC_V6_FLTR:
break;
default:
ipgpc0dbg(("ipgpc_removefilter(): invalid filter type %d",
return (EINVAL);
}
/* remove filter from filter list */
/* remove filter id from class' list of filters */
return (0);
}
/*
* removecid(in_class_id)
*
* removes the cid entry from the cid list and frees allocated structures
*/
static void
removecid(int in_class_id)
{
/* delete kstat entry */
}
/* decrement total number of classes loaded */
}
/*
* remove_from_cid_filter_list(in_class_id, in_filter_id)
*
* removes the input filter_id from the filter_list of the class associated
* with the input class_id
*/
static void
{
}
}
/*
* ipgpc_removeclass(class_name)
*
* removes a class and all the filters that point to it (ouch!)
* - returns 0 on success
* - ENOENT if class name does not exist
* - ENOTSUP if class name equals 'default'
*/
int
{
unsigned class_id;
int rc;
/* check to see if any classes are loaded */
if (ipgpc_num_cls == 0) {
return (ENOENT);
}
/* lookup class name, only classes that exist can be removed */
!= EEXIST) {
return (rc);
}
if (class_id == ipgpc_def_class_id) {
ipgpc0dbg(("ipgpc_removeclass(): default class may not be " \
"removed"));
return (ENOTSUP);
}
} else {
/* free this node */
}
}
/* remove cid from ipgpc_cid_list and decrement ipgpc_num_cls */
ipgpc3dbg(("ipgpc_removeclass: class %s has been removed",
class_name));
return (0);
}
/*
* ipgpc_modifyfilter(nvlist, flags)
*
* modifies the input filter
* - if in_class != NULL, filter is associated with that class
* - EINVAL is returned if filter name does not exist in nvlist
* - if filter->filter_name does not exist ENOENT is returned
* - if a class name to associate with is not present in nvlist, then the
* previous class association is used
*/
int
{
unsigned filter_id;
int ret = 0;
int rc;
char *name;
char *s;
ipgpc0dbg(("ipgpc_modifyfilter: error %d parsing filter",
ret));
return (ret);
}
/* parse class name */
!= 0) {
}
/* modify filter entry */
/* set class_name to previous class_name association */
} else {
ipgpc_num_cls)) != EEXIST) {
ipgpc0dbg(("ipgpc_modifyfilter: class does " \
"not exist"));
return (ret);
}
}
/* copy out old filter just in case we need to revert */
/* make copy of filter_comment */
} else {
}
/* make copy of saddr_hostname */
} else {
}
/* make copy of daddr_hostname */
} else {
}
/* remove old filter entry */
if (ret == 0) { /* no error, add filter */
if (ret != 0) {
/* error occured, free filter fields */
ipgpc0dbg(("ipgpc_modifyfilter: invalid " \
"filter given, unable to modify " \
"existing filter %s",
filter->filter_name));
/* revert back to old filter */
flags);
return (ret);
}
} else {
ipgpc0dbg(("ipgpc_modifyfilter: error %d occured " \
"when modifying filter", ret));
return (ret);
}
} else {
return (rc); /* filter name does not exist */
}
return (0);
}
/*
* ipgpc_modifyclass(in_class)
*
* if the input class exists, then the action list is modified
* if the input class does not exist, ENOENT is returned
*/
/* ARGSUSED */
int
{
unsigned class_id;
char *name;
int rc;
/* parse class name */
return (EINVAL); /* class name missing, error */
}
/* check for max name length */
ipgpc0dbg(("ipgpc_modifyclass: class name length > " \
"MAXNAMELEN"));
return (EINVAL);
}
/* look up class name, only existing classes can be modified */
ipgpc_num_cls)) == EEXIST) {
/* preserve previous config if values are absent */
/* parse action name */
!= 0) {
/* use previous config */
} else { /* next action name present */
== IPP_ACTION_INVAL) {
ipgpc0dbg(("ipgpc_modifyclass: invalid " \
"action name %s", name));
return (EINVAL); /* this is an error */
}
ref_action = B_TRUE;
}
/* parse gather stats byte */
&gather_stats) != 0) {
/* use previous config */
} else {
}
/* check to see if gather_stats booleans differ */
in_class.gather_stats)) {
B_TRUE) {
/* delete kstat entry */
cl_stats =
}
} else { /* gather_stats == B_FALSE */
!= 0) {
ipgpc0dbg(("ipgpc_modifyclass: " \
"class_statinit failed with " \
"error %d", rc));
return (rc);
}
}
}
/* check if next_action was modified */
if (ref_action == B_TRUE) {
in_class.next_action, 0)) != 0) {
ipgpc0dbg(("ipgpc_modifyclass: error " \
"occured while adding a reference to " \
"the new next_action %d",
return (rc);
}
/* fix up references */
flags);
}
/* preserve originator id */
} else {
ipgpc0dbg(("ipgpc_modifyclass: class name lookup error %d",
rc));
return (rc);
}
return (0);
}
/*
* ipgpc_list_insert(listpp, id)
*
* inserts an item, id, into the list, if item exists EEXIST is returned
*/
int
{
element_node_t *p;
} else {
(*p->element_ref)(p);
return (EEXIST);
}
}
(*p->element_ref)(p);
return (EEXIST);
} else {
p->next =
p = p->next;
}
}
return (0);
}
/*
* ipgpc_list_remove(listpp, id)
*
* removes an item, id, from the list if it exists and returns TRUE or FALSE
* if not removed
*/
{
element_node_t *p = NULL;
element_node_t *t = NULL;
return (B_FALSE);
}
p = *listpp;
}
(*p->element_unref)(p);
return (B_TRUE);
/* linear search for matching id */
t = p->next;
}
(*t->element_unref)(t);
return (B_TRUE);
}
}
}
return (B_FALSE);
}
/*
* Module destroy code
*/
static void
{
int i;
for (i = 0; i < ipgpc_max_num_classes; ++i) {
if (ipgpc_cid_list[i].info > 0) {
(void) ipgpc_removeclass(
}
}
}
static void
{
int sp = 0;
/* loop until only the root node remains */
} else { /* leaf node reached */
/* free leaf node and pop the stack */
} else {
}
return;
}
}
}
}
void
{
int i;
int rc;
/* check to see if default class id was set */
if (ipgpc_def_class_id != -1) {
/* unreference default_class->next_action */
/* removing filter associated with the default class */
(void) ipgpc_removefilter(
} else {
/* free this node */
}
}
ipgpc_def_class_id = -1;
}
/* remove stats entries */
if (ipgpc_global_stats != NULL) {
/* destroy global stats */
}
/*
* remove all classes, which will remove all filters, stats and
* selectors
*/
if (ipgpc_cid_list != NULL) {
sizeof (cid_t) * ipgpc_max_num_classes);
}
/* all filters and classes should have been removed at this point */
/* free filter id list structure */
if (ipgpc_fid_list != NULL) {
sizeof (fid_t) * ipgpc_max_num_filters);
}
/*
* IPv6 address tries don't implement path compression or node
* before trie root node is destroyed
*/
/* free trie root */
/* destroy lock */
}
/* free trie root */
/* destroy lock */
}
/* free remaining tries structures */
for (i = 0; i < (NUM_TRIES - 2); ++i) {
/* free trie root */
ipgpc_trie_list[i].trie);
/* destroy lock */
}
}
/* destroy caches */
if (ht_node_cache != NULL) {
}
if (trie_node_cache != NULL) {
}
if (element_node_cache != NULL) {
}
if (ht_match_cache != NULL) {
}
}
/*
* Module info code
*/
/*
* ipgpc_params_info(fn, arg)
*
* allocates, builds and passes an nvlist to fn with arg
*/
int
{
int rc;
/* allocate nvlist to be passed back */
return (rc);
}
/* add config type */
return (rc);
}
/* add gather stats boolean */
(uint32_t)ipgpc_gather_stats)) != 0) {
return (rc);
}
/* call back with nvlist */
return (rc);
}
/*
* build_class_nvlist(nvlpp, in_class)
*
* build an nvlist based on in_class
* if isdefault, add apporiate configuration type to nvlpp
*/
static int
{
char *next_action;
int rc;
/*
* add configuration type
* if class is the default class, config type should be
* CLASSIFIER_MODIFY_CLASS
* otherwise it should be CLASSIFIER_ADD_CLASS
*/
/* add config type */
!= 0) {
return (rc);
}
/* add class name */
in_class->class_name)) != 0) {
return (rc);
}
/* add originator */
in_class->originator)) != 0) {
return (rc);
}
/* look up next action name with next action id */
return (rc);
}
/* add next action name */
next_action)) != 0) {
return (rc);
}
/* add gather stats boolean */
return (rc);
}
return (0);
}
/*
* ipgpc_classes_info(fn, arg)
*
* foreach class, allocate, build and pass an nvlist to fn with arg
*/
int
{
int i;
int rc;
for (i = 0; i < ipgpc_max_num_classes; ++i) {
if (ipgpc_cid_list[i].info <= 0) {
/* cid not allocated for this entry */
continue;
}
/* allocate an nvlist */
!= 0) {
return (rc);
}
/* build an nvlist for this particular class */
&ipgpc_cid_list[i].aclass,
return (rc);
}
/* call back with nvlist */
return (rc);
}
}
return (0);
}
/*
* build_filter_nvlist(nvlpp, in_filter, class_name)
*
* build an nvlist based on in_filter and class_name.
* Only non-wildcard/dontcare selectors are added to the nvlist.
*/
static int
char *class_name)
{
int rc;
/* add filter name */
in_filter->filter_name)) != 0) {
return (rc);
}
/* add class name */
!= 0) {
return (rc);
}
/* add originator */
in_filter->originator)) != 0) {
return (rc);
}
/* add configuration type of CLASSIFIER_ADD_FILTER */
CLASSIFIER_ADD_FILTER)) != 0) {
return (rc);
}
/* add interface groupname */
in_filter->if_groupname)) != 0) {
return (rc);
}
}
/* add uid */
!= 0) {
return (rc);
}
}
/* add projid */
return (rc);
}
}
/* add interface index */
return (rc);
}
}
/* add direction */
return (rc);
}
}
/* add protocol */
!= 0) {
return (rc);
}
}
/* add dsfield and mask */
if (in_filter->dsfield_mask != 0) {
return (rc);
}
in_filter->dsfield_mask)) != 0) {
return (rc);
}
}
/* add source address, mask and hostname */
return (rc);
}
return (rc);
}
in_filter->saddr_hostname)) != 0) {
return (rc);
}
}
}
/* add destination address, mask and hostname */
return (rc);
}
return (rc);
}
in_filter->daddr_hostname)) != 0) {
return (rc);
}
}
}
/* add source port and mask */
if (in_filter->sport_mask != 0) {
return (rc);
}
in_filter->sport_mask)) != 0) {
return (rc);
}
}
/* add destination port and mask */
if (in_filter->dport_mask != 0) {
return (rc);
}
in_filter->dport_mask)) != 0) {
return (rc);
}
}
/* add precedence */
in_filter->precedence)) != 0) {
return (rc);
}
}
/* add priority */
return (rc);
}
}
/* add filter type */
in_filter->filter_type)) != 0) {
return (rc);
}
}
/* add filter instance */
in_filter->filter_instance)) != 0) {
return (rc);
}
}
/* add filter private field */
in_filter->filter_comment)) != 0) {
return (rc);
}
}
return (0);
}
/*
* ipgpc_filters_info(fn, arg)
*
* for each filter, allocate, build and pass an nvlist to fn with arg
*/
int
{
int i;
int rc;
int class_id;
for (i = 0; i < ipgpc_max_num_filters; ++i) {
if (ipgpc_fid_list[i].info <= 0) {
/* fid not allocated for this entry */
continue;
}
/* allocate an nvlist */
!= 0) {
return (rc);
}
/* build an nvlist for this particular filter */
&ipgpc_fid_list[i].filter,
return (rc);
}
/* call back with nvlist */
return (rc);
}
}
return (0);
}
/*
* Module invoke code
*/
/*
* ipgpc_findfilters(in_id, key, fid_table)
*
* returns a list of matching filters for searching the given structure
* associated with the input id with the input key
* - returns DONTCARE_ONLY_MATCH if the selector structure described by
* in_id contains only dontcares
* - returns NO_MATCHES if no filters were found and no dontcares exist
* for a given selector
* - ENOMEM is returned if memory error occurs
* - NORMAL_MATCH on success
*/
int
{
int num_found = 0;
/* trie is loaded with only DONTCARE(*) keys */
return (DONTCARE_ONLY_MATCH);
}
/* check to see if no matches were made */
if ((num_found == 0) &&
return (NO_MATCHES);
}
/* trie is loaded with only DONTCARE(*) keys */
return (DONTCARE_ONLY_MATCH);
}
/* check to see if no matches were made */
return (NO_MATCHES);
}
} else { /* trie to search */
/* trie is loaded with only DONTCARE(*) keys */
return (DONTCARE_ONLY_MATCH);
}
/* search the trie for matches */
/* check to see if no matches were made */
return (NO_MATCHES);
}
}
return (ENOMEM);
} else {
return (NORMAL_MATCH);
}
}
/*
* ipgpc_findfilters6(in_id, key, fid_table)
*
* findfilters specific to IPv6 traffic
*/
int
{
int num_found = 0;
/* trie is loaded with only DONTCARE(*) keys */
return (DONTCARE_ONLY_MATCH);
}
/* search the trie for matches */
/* check to see if no matches were made */
return (NO_MATCHES);
return (ENOMEM);
} else {
return (NORMAL_MATCH);
}
}
/*
* ht_match_insert(a, id, mask)
*
* inserts id into table and applies mask to match_map
* returns ENOMEM if can't allocate ht_match_t node, 0 otherwise
*/
static int
{
ht_match_t *p = NULL;
ipgpc0dbg(("ht_match_insert(): kmem_cache_alloc " \
"error"));
return (ENOMEM);
}
} else {
p = a[x].next;
while (p != NULL) {
return (0);
}
p = p->next;
}
if (p == NULL) {
ipgpc0dbg(("ht_match_insert(): kmem_cache_alloc " \
"error"));
return (ENOMEM);
}
a[x].next = p;
}
return (0);
}
/*
* ipgpc_mark_found(mask, list, fid_table)
*
* given a list of filter ids and a mask for the selector that is being marked,
* the ids are inserted (or updated) in the fid_table to being marked as
* matched for the given selector
* return -1 if memory error
*/
int
{
int num_found = 0;
/* apply the trie mask to the match map for this element */
== ENOMEM) {
return (-1);
}
++num_found;
}
}
return (num_found);
}
/* updates global stats for ipgpc */
/* ARGSUSED */
static int
{
return (0);
}
/* updates class stats for a specific class */
static int
{
return (0);
}