258 PROJID_MASK);
259 /* IF_INDEX selector structure */
260 insert_ipgpc_table_list_info(IF_IDX, if_table, IPGPC_UNSPECIFIED,
261 IF_MASK);
262 /* DIR selector structure */
263 insert_ipgpc_table_list_info(DIR_IDX, dir_table, IPGPC_UNSPECIFIED,
264 DIR_MASK);
265 }
266
267 static void
268 initialize_ba_tables(void)
269 {
270 /* DS (ToS/Traffic Class) field structure */
271 ipgpc_ds_table_id.info.mask = DS_MASK;
272 ipgpc_ds_table_id.info.dontcareonly = B_TRUE;
273 }
274
275 static void
276 element_node_ref(element_node_t *element)
277 {
278 atomic_add_32(&element->element_refcnt, 1);
279 ASSERT(element->element_refcnt > 1);
280 }
281
282 static void
283 element_node_unref(element_node_t *element)
284 {
285 ASSERT(element->element_refcnt > 0);
286 if (atomic_add_32_nv(&element->element_refcnt, -1) == 0) {
287 kmem_cache_free(element_node_cache, element);
288 }
289 }
290
291 /* ARGSUSED1 */
292 static int
293 element_node_cache_constructor(void *buf, void *cdrarg, int kmflags)
294 {
295 element_node_t *node = buf;
296
297 node->element_ref = element_node_ref;
298 node->element_unref = element_node_unref;
299 return (0);
300 }
301
302 /* prime values to be used for hashing of filter and class tables */
303 #define IPGPC_PRIMES() {0, 0, 0, 5, 11, 23, 47, 89, 191, 383, 503, 761, \
304 1009, 1531, 2003, 2503, 3067, 3511, 4001, 5003, 6143, \
305 10007, 12281, 15013, 20011, 24571, 49139, 98299, \
306 100003, 196597, 393209, 786431, 1000003, 1251409, \
1119 }
1120 /* check to see if this is a catch all filter, which we reject */
1121 if (fid->insert_map == 0) {
1122 ipgpc0dbg(("ipgpc_addfilter(): filter %s rejected because " \
1123 "catch all filters are not supported\n",
1124 filter->filter_name));
1125 /* cleanup what we allocated */
1126 /* remove filter from filter list */
1127 ipgpc_fid_list[filter_id].info = -1;
1128 ipgpc_fid_list[filter_id].filter.filter_name[0] = '\0';
1129 reset_dontcare_stats(); /* need to fixup stats */
1130 mutex_exit(&ipgpc_fid_list_lock);
1131 return (EINVAL);
1132 } else { /* associate filter with class */
1133 mutex_enter(&ipgpc_cid_list_lock);
1134 (void) ipgpc_list_insert(&ipgpc_cid_list[class_id].filter_list,
1135 filter_id);
1136 mutex_exit(&ipgpc_cid_list_lock);
1137 }
1138 mutex_exit(&ipgpc_fid_list_lock);
1139 atomic_add_long(&ipgpc_num_fltrs, 1);
1140 ipgpc3dbg(("ipgpc_addfilter: adding filter %s", filter->filter_name));
1141 return (0);
1142 }
1143
1144 /*
1145 * reset_dontcare_stats()
1146 *
1147 * when an insertion fails because zero selectors are specified in a filter
1148 * the number of dontcare's recorded for each selector structure needs to be
1149 * decremented
1150 */
1151 static void
1152 reset_dontcare_stats(void)
1153 {
1154 int i;
1155
1156 for (i = 0; i < NUM_TRIES; ++i) {
1157 atomic_add_32(&ipgpc_trie_list[i].stats.num_dontcare, -1);
1158 }
1159 for (i = 0; i < NUM_TABLES; ++i) {
1160 atomic_add_32(&ipgpc_table_list[i].stats.num_dontcare, -1);
1161 }
1162 atomic_add_32(&ipgpc_ds_table_id.stats.num_dontcare, -1);
1163 }
1164
1165 /*
1166 * ipgpc_parse_class(out_class, nvlp)
1167 *
1168 * Given a name value pair list, a class structure will be parsed.
1169 * To be a valid class, the class name, originator id and next action name
1170 * must be present. gather_stats is optional, if absent default value is used
1171 */
1172 int
1173 ipgpc_parse_class(ipgpc_class_t *out_class, nvlist_t *nvlp)
1174 {
1175 char *name;
1176 size_t name_len;
1177 uint32_t gather_stats;
1178
1179 /* parse class name */
1180 if (nvlist_lookup_string(nvlp, CLASSIFIER_CLASS_NAME, &name) != 0) {
1181 return (EINVAL); /* class name missing, error */
1182 }
1340 /* create new filter list for new class */
1341 ipgpc_cid_list[class_id].info = 1;
1342 ipgpc_cid_list[class_id].aclass = *in_class;
1343 if (in_class->gather_stats == B_TRUE) {
1344 /* init kstat entry */
1345 if ((rc = class_statinit(in_class, class_id)) != 0) {
1346 ipgpc_cid_list[class_id].info = -1;
1347 ipgpc0dbg(("insertcid: "
1348 "class_statinit failed with error %d", rc));
1349 mutex_exit(&ipgpc_cid_list_lock);
1350 return (rc);
1351 }
1352 } else {
1353 ipgpc_cid_list[class_id].cl_stats = NULL;
1354 }
1355 ipgpc3dbg(("insertcid: adding class %s",
1356 in_class->class_name));
1357 bcopy(in_class->class_name,
1358 ipgpc_cid_list[class_id].aclass.class_name, MAXNAMELEN);
1359 ipgpc_cid_list[class_id].filter_list = NULL;
1360 atomic_add_long(&ipgpc_num_cls, 1);
1361 } else {
1362 ipgpc0dbg(("insertcid: class name lookup error %d", err));
1363 mutex_exit(&ipgpc_cid_list_lock);
1364 return (err);
1365 }
1366 mutex_exit(&ipgpc_cid_list_lock);
1367 *out_class_id = class_id;
1368 return (err);
1369 }
1370
1371 /*
1372 * common_removefilter(in_filter_id, fid)
1373 *
1374 * removes in_filter_id from each of the common selector structures
1375 */
1376 static void
1377 common_removefilter(int in_filter_id, fid_t *fid)
1378 {
1379 /* start trie removes */
1380 t_remove(&ipgpc_trie_list[IPGPC_TRIE_SPORTID], in_filter_id,
1487 break;
1488 case IPGPC_V6_FLTR:
1489 common_removefilter(filter_id, fid);
1490 v6_removefilter(filter_id, fid);
1491 break;
1492 default:
1493 ipgpc0dbg(("ipgpc_removefilter(): invalid filter type %d",
1494 fid->filter.filter_type));
1495 mutex_exit(&ipgpc_fid_list_lock);
1496 return (EINVAL);
1497 }
1498 /* remove filter from filter list */
1499 ipgpc_fid_list[filter_id].info = -1;
1500 ipgpc_fid_list[filter_id].insert_map = 0;
1501 ipgpc_fid_list[filter_id].filter.filter_name[0] = '\0';
1502 ipgpc_filter_destructor(&ipgpc_fid_list[filter_id].filter);
1503 mutex_exit(&ipgpc_fid_list_lock);
1504 /* remove filter id from class' list of filters */
1505 remove_from_cid_filter_list(ipgpc_fid_list[filter_id].class_id,
1506 filter_id);
1507 atomic_add_long(&ipgpc_num_fltrs, -1);
1508 return (0);
1509 }
1510
1511 /*
1512 * removecid(in_class_id)
1513 *
1514 * removes the cid entry from the cid list and frees allocated structures
1515 */
1516 static void
1517 removecid(int in_class_id)
1518 {
1519 ipgpc_cid_list[in_class_id].info = -1;
1520 ipgpc_cid_list[in_class_id].aclass.class_name[0] = '\0';
1521 ipgpc_cid_list[in_class_id].aclass.next_action = -1;
1522 /* delete kstat entry */
1523 if (ipgpc_cid_list[in_class_id].cl_stats != NULL) {
1524 ipp_stat_destroy(ipgpc_cid_list[in_class_id].cl_stats);
1525 ipgpc_cid_list[in_class_id].cl_stats = NULL;
1526 }
1527 /* decrement total number of classes loaded */
1528 atomic_add_long(&ipgpc_num_cls, -1);
1529 }
1530
1531 /*
1532 * remove_from_cid_filter_list(in_class_id, in_filter_id)
1533 *
1534 * removes the input filter_id from the filter_list of the class associated
1535 * with the input class_id
1536 */
1537 static void
1538 remove_from_cid_filter_list(int in_class_id, int in_filter_id)
1539 {
1540 cid_t *cid = &ipgpc_cid_list[in_class_id];
1541
1542 if (cid->filter_list != NULL) {
1543 (void) ipgpc_list_remove(&cid->filter_list, in_filter_id);
1544 }
1545 }
1546
1547 /*
1548 * ipgpc_removeclass(class_name)
|
258 PROJID_MASK);
259 /* IF_INDEX selector structure */
260 insert_ipgpc_table_list_info(IF_IDX, if_table, IPGPC_UNSPECIFIED,
261 IF_MASK);
262 /* DIR selector structure */
263 insert_ipgpc_table_list_info(DIR_IDX, dir_table, IPGPC_UNSPECIFIED,
264 DIR_MASK);
265 }
266
267 static void
268 initialize_ba_tables(void)
269 {
270 /* DS (ToS/Traffic Class) field structure */
271 ipgpc_ds_table_id.info.mask = DS_MASK;
272 ipgpc_ds_table_id.info.dontcareonly = B_TRUE;
273 }
274
275 static void
276 element_node_ref(element_node_t *element)
277 {
278 atomic_inc_32(&element->element_refcnt);
279 ASSERT(element->element_refcnt > 1);
280 }
281
282 static void
283 element_node_unref(element_node_t *element)
284 {
285 ASSERT(element->element_refcnt > 0);
286 if (atomic_dec_32_nv(&element->element_refcnt) == 0) {
287 kmem_cache_free(element_node_cache, element);
288 }
289 }
290
291 /* ARGSUSED1 */
292 static int
293 element_node_cache_constructor(void *buf, void *cdrarg, int kmflags)
294 {
295 element_node_t *node = buf;
296
297 node->element_ref = element_node_ref;
298 node->element_unref = element_node_unref;
299 return (0);
300 }
301
302 /* prime values to be used for hashing of filter and class tables */
303 #define IPGPC_PRIMES() {0, 0, 0, 5, 11, 23, 47, 89, 191, 383, 503, 761, \
304 1009, 1531, 2003, 2503, 3067, 3511, 4001, 5003, 6143, \
305 10007, 12281, 15013, 20011, 24571, 49139, 98299, \
306 100003, 196597, 393209, 786431, 1000003, 1251409, \
1119 }
1120 /* check to see if this is a catch all filter, which we reject */
1121 if (fid->insert_map == 0) {
1122 ipgpc0dbg(("ipgpc_addfilter(): filter %s rejected because " \
1123 "catch all filters are not supported\n",
1124 filter->filter_name));
1125 /* cleanup what we allocated */
1126 /* remove filter from filter list */
1127 ipgpc_fid_list[filter_id].info = -1;
1128 ipgpc_fid_list[filter_id].filter.filter_name[0] = '\0';
1129 reset_dontcare_stats(); /* need to fixup stats */
1130 mutex_exit(&ipgpc_fid_list_lock);
1131 return (EINVAL);
1132 } else { /* associate filter with class */
1133 mutex_enter(&ipgpc_cid_list_lock);
1134 (void) ipgpc_list_insert(&ipgpc_cid_list[class_id].filter_list,
1135 filter_id);
1136 mutex_exit(&ipgpc_cid_list_lock);
1137 }
1138 mutex_exit(&ipgpc_fid_list_lock);
1139 atomic_inc_ulong(&ipgpc_num_fltrs);
1140 ipgpc3dbg(("ipgpc_addfilter: adding filter %s", filter->filter_name));
1141 return (0);
1142 }
1143
1144 /*
1145 * reset_dontcare_stats()
1146 *
1147 * when an insertion fails because zero selectors are specified in a filter
1148 * the number of dontcare's recorded for each selector structure needs to be
1149 * decremented
1150 */
1151 static void
1152 reset_dontcare_stats(void)
1153 {
1154 int i;
1155
1156 for (i = 0; i < NUM_TRIES; ++i) {
1157 atomic_dec_32(&ipgpc_trie_list[i].stats.num_dontcare);
1158 }
1159 for (i = 0; i < NUM_TABLES; ++i) {
1160 atomic_dec_32(&ipgpc_table_list[i].stats.num_dontcare);
1161 }
1162 atomic_dec_32(&ipgpc_ds_table_id.stats.num_dontcare);
1163 }
1164
1165 /*
1166 * ipgpc_parse_class(out_class, nvlp)
1167 *
1168 * Given a name value pair list, a class structure will be parsed.
1169 * To be a valid class, the class name, originator id and next action name
1170 * must be present. gather_stats is optional, if absent default value is used
1171 */
1172 int
1173 ipgpc_parse_class(ipgpc_class_t *out_class, nvlist_t *nvlp)
1174 {
1175 char *name;
1176 size_t name_len;
1177 uint32_t gather_stats;
1178
1179 /* parse class name */
1180 if (nvlist_lookup_string(nvlp, CLASSIFIER_CLASS_NAME, &name) != 0) {
1181 return (EINVAL); /* class name missing, error */
1182 }
1340 /* create new filter list for new class */
1341 ipgpc_cid_list[class_id].info = 1;
1342 ipgpc_cid_list[class_id].aclass = *in_class;
1343 if (in_class->gather_stats == B_TRUE) {
1344 /* init kstat entry */
1345 if ((rc = class_statinit(in_class, class_id)) != 0) {
1346 ipgpc_cid_list[class_id].info = -1;
1347 ipgpc0dbg(("insertcid: "
1348 "class_statinit failed with error %d", rc));
1349 mutex_exit(&ipgpc_cid_list_lock);
1350 return (rc);
1351 }
1352 } else {
1353 ipgpc_cid_list[class_id].cl_stats = NULL;
1354 }
1355 ipgpc3dbg(("insertcid: adding class %s",
1356 in_class->class_name));
1357 bcopy(in_class->class_name,
1358 ipgpc_cid_list[class_id].aclass.class_name, MAXNAMELEN);
1359 ipgpc_cid_list[class_id].filter_list = NULL;
1360 atomic_inc_ulong(&ipgpc_num_cls);
1361 } else {
1362 ipgpc0dbg(("insertcid: class name lookup error %d", err));
1363 mutex_exit(&ipgpc_cid_list_lock);
1364 return (err);
1365 }
1366 mutex_exit(&ipgpc_cid_list_lock);
1367 *out_class_id = class_id;
1368 return (err);
1369 }
1370
1371 /*
1372 * common_removefilter(in_filter_id, fid)
1373 *
1374 * removes in_filter_id from each of the common selector structures
1375 */
1376 static void
1377 common_removefilter(int in_filter_id, fid_t *fid)
1378 {
1379 /* start trie removes */
1380 t_remove(&ipgpc_trie_list[IPGPC_TRIE_SPORTID], in_filter_id,
1487 break;
1488 case IPGPC_V6_FLTR:
1489 common_removefilter(filter_id, fid);
1490 v6_removefilter(filter_id, fid);
1491 break;
1492 default:
1493 ipgpc0dbg(("ipgpc_removefilter(): invalid filter type %d",
1494 fid->filter.filter_type));
1495 mutex_exit(&ipgpc_fid_list_lock);
1496 return (EINVAL);
1497 }
1498 /* remove filter from filter list */
1499 ipgpc_fid_list[filter_id].info = -1;
1500 ipgpc_fid_list[filter_id].insert_map = 0;
1501 ipgpc_fid_list[filter_id].filter.filter_name[0] = '\0';
1502 ipgpc_filter_destructor(&ipgpc_fid_list[filter_id].filter);
1503 mutex_exit(&ipgpc_fid_list_lock);
1504 /* remove filter id from class' list of filters */
1505 remove_from_cid_filter_list(ipgpc_fid_list[filter_id].class_id,
1506 filter_id);
1507 atomic_dec_ulong(&ipgpc_num_fltrs);
1508 return (0);
1509 }
1510
1511 /*
1512 * removecid(in_class_id)
1513 *
1514 * removes the cid entry from the cid list and frees allocated structures
1515 */
1516 static void
1517 removecid(int in_class_id)
1518 {
1519 ipgpc_cid_list[in_class_id].info = -1;
1520 ipgpc_cid_list[in_class_id].aclass.class_name[0] = '\0';
1521 ipgpc_cid_list[in_class_id].aclass.next_action = -1;
1522 /* delete kstat entry */
1523 if (ipgpc_cid_list[in_class_id].cl_stats != NULL) {
1524 ipp_stat_destroy(ipgpc_cid_list[in_class_id].cl_stats);
1525 ipgpc_cid_list[in_class_id].cl_stats = NULL;
1526 }
1527 /* decrement total number of classes loaded */
1528 atomic_dec_ulong(&ipgpc_num_cls);
1529 }
1530
1531 /*
1532 * remove_from_cid_filter_list(in_class_id, in_filter_id)
1533 *
1534 * removes the input filter_id from the filter_list of the class associated
1535 * with the input class_id
1536 */
1537 static void
1538 remove_from_cid_filter_list(int in_class_id, int in_filter_id)
1539 {
1540 cid_t *cid = &ipgpc_cid_list[in_class_id];
1541
1542 if (cid->filter_list != NULL) {
1543 (void) ipgpc_list_remove(&cid->filter_list, in_filter_id);
1544 }
1545 }
1546
1547 /*
1548 * ipgpc_removeclass(class_name)
|