Print this page
5045 use atomic_{inc,dec}_* instead of atomic_add_*
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/ipp/ipgpc/filters.c
+++ new/usr/src/uts/common/ipp/ipgpc/filters.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26 #include <sys/atomic.h>
27 27 #include <sys/types.h>
28 28 #include <sys/systm.h>
29 29 #include <netinet/in.h>
30 30 #include <netinet/ip6.h>
31 31 #include <inet/common.h>
32 32 #include <inet/ip.h>
33 33 #include <inet/ip6.h>
34 34 #include <ipp/ipp_config.h>
35 35 #include <ipp/ipgpc/filters.h>
36 36 #include <ipp/ipgpc/trie.h>
37 37 #include <ipp/ipgpc/table.h>
38 38 #include <ipp/ipgpc/ba_table.h>
39 39 #include <ipp/ipgpc/classifier.h>
40 40
41 41 /* Implementation for filter management and configuration support of ipgpc */
42 42
43 43 #define BITLENGTH(x) (sizeof (x) * NBBY)
44 44
45 45 /* Globals */
46 46 kmutex_t ipgpc_table_list_lock; /* table list lock */
47 47 kmutex_t ipgpc_fid_list_lock; /* filter id list lock */
48 48 kmutex_t ipgpc_cid_list_lock; /* class id list lock */
49 49 trie_id_t ipgpc_trie_list[NUM_TRIES]; /* list of all trie structures ids */
50 50 table_id_t ipgpc_table_list[NUM_TABLES]; /* list of all table ids */
51 51 ba_table_id_t ipgpc_ds_table_id; /* DiffServ field table id */
52 52 fid_t *ipgpc_fid_list = NULL; /* filter id list */
53 53 cid_t *ipgpc_cid_list = NULL; /* class id list */
54 54 kmem_cache_t *ht_node_cache = NULL; /* hashtable cache */
55 55 kmem_cache_t *ht_match_cache = NULL; /* ht_match cache */
56 56 kmem_cache_t *trie_node_cache = NULL; /* trie node cache */
57 57 kmem_cache_t *element_node_cache = NULL; /* element node cache */
58 58 boolean_t ipgpc_gather_stats; /* should stats be performed for ipgpc */
59 59 uint64_t ipgpc_npackets; /* number of packets stat */
60 60 uint64_t ipgpc_nbytes; /* number of bytes stat */
61 61 uint64_t ipgpc_epackets; /* number of packets in error */
62 62 int ipgpc_def_class_id = -1; /* class id of default class */
63 63 size_t ipgpc_num_fltrs; /* number of loaded filter */
64 64 size_t ipgpc_num_cls; /* number of loaded classes */
65 65 /* max number of allowable filters */
66 66 size_t ipgpc_max_num_filters = IPGPC_DEFAULT_MAX_FILTERS;
67 67 /* max number of allowable classes */
68 68 size_t ipgpc_max_num_classes = IPGPC_DEFAULT_MAX_CLASSES;
69 69 size_t ipgpc_max_filters = 0; /* set in /etc/system */
70 70 size_t ipgpc_max_classes = 0; /* set in /etc/system */
71 71 ipp_stat_t *ipgpc_global_stats = NULL; /* global stats structure */
72 72
73 73 /* Statics */
74 74 static trie saddr_trie; /* IPv4 source address trie */
75 75 static trie daddr_trie; /* IPv4 destination address trie */
76 76 static trie sport_trie; /* source port trie */
77 77 static trie dport_trie; /* destination port trie */
78 78 static trie saddr6_trie; /* IPv6 source address trie */
79 79 static trie daddr6_trie; /* IPv6 destination address trie */
80 80 static ht_node_t proto_table[TABLE_SIZE]; /* protocol table */
81 81 static ht_node_t uid_table[TABLE_SIZE]; /* IPGPC_UID table */
82 82 static ht_node_t projid_table[TABLE_SIZE]; /* IPGPC_PROJID table */
83 83 static ht_node_t if_table[TABLE_SIZE]; /* Interface ID table */
84 84 static ht_node_t dir_table[TABLE_SIZE]; /* packet direction table */
85 85 static ipp_action_id_t ipgpc_aid; /* the action id for ipgpc */
86 86
87 87 static int global_statinit(void);
88 88 static void insert_ipgpc_trie_list_info(int, size_t, trie, uint16_t);
89 89 static int initialize_tries(void);
90 90 static void insert_ipgpc_table_list_info(int, hash_table, int, uint16_t);
91 91 static void initialize_tables(void);
92 92 static void initialize_ba_tables(void);
93 93 static void element_node_ref(element_node_t *);
94 94 static void element_node_unref(element_node_t *);
95 95 static int element_node_cache_constructor(void *, void *, int);
96 96 static int filter_name2id(unsigned *, char[], int32_t, int);
97 97 static int class_name2id(unsigned *, char[], int);
98 98 static boolean_t iscontinuousmask(uint32_t, uint8_t);
99 99 static void insertfid(int, ipgpc_filter_t *, uint_t);
100 100 static void common_addfilter(fid_t *, int);
101 101 static void v4_addfilter(fid_t *, int);
102 102 static void v6_addfilter(fid_t *, int);
103 103 static void reset_dontcare_stats(void);
104 104 static int class_statinit(ipgpc_class_t *, int);
105 105 static int insertcid(ipgpc_class_t *, int *);
106 106 static void common_removefilter(int, fid_t *);
107 107 static void v4_removefilter(int, fid_t *);
108 108 static void v6_removefilter(int, fid_t *);
109 109 static void removecid(int);
110 110 static void remove_from_cid_filter_list(int, int);
111 111 static void removeclasses(ipp_flags_t);
112 112 static void freetriev6nodes(node_t **);
113 113 static int ht_match_insert(ht_match_t *, int, uint16_t);
114 114 static int update_class_stats(ipp_stat_t *, void *, int);
115 115 static int update_global_stats(ipp_stat_t *, void *, int);
116 116 static int build_class_nvlist(nvlist_t **, ipgpc_class_t *, boolean_t);
117 117 static int build_filter_nvlist(nvlist_t **, ipgpc_filter_t *, char *);
118 118
119 119
120 120 /*
121 121 * Module initialization code
122 122 */
123 123
124 124 /*
125 125 * global_statinit()
126 126 *
127 127 * initializes global stats for ipgpc action module.
128 128 * global include:
129 129 * - number of filters loaded
130 130 * - number of classes loaded
131 131 * - number of packets that have passed through ipgpc since action create
132 132 * - number of bytes that have passed through ipgpc since action create
133 133 * if ipp_stat_create fails, an error code is returned
134 134 * if ipp_stat_named_init fails, an error code is returned
135 135 * 0 is returned on success
136 136 */
137 137 static int
138 138 global_statinit(void)
139 139 {
140 140 int rc;
141 141 globalstats_t *gblsnames = NULL;
142 142
143 143 /* create stat structure */
144 144 if ((rc = ipp_stat_create(ipgpc_aid, "ipgpc_global_stats", 5,
145 145 update_global_stats, NULL, &ipgpc_global_stats)) != 0) {
146 146 ipgpc0dbg(("global_statinit: error creating ipp_stat entry"));
147 147 return (rc);
148 148 }
149 149
150 150 ASSERT(ipgpc_global_stats != NULL);
151 151 gblsnames = (globalstats_t *)ipgpc_global_stats->ipps_data;
152 152 ASSERT(gblsnames != NULL);
153 153
154 154 /* add stat name entries */
155 155 if ((rc = ipp_stat_named_init(ipgpc_global_stats, "nfilters",
156 156 IPP_STAT_UINT32, &gblsnames->nfilters)) != 0) {
157 157 return (rc);
158 158 }
159 159 if ((rc = ipp_stat_named_init(ipgpc_global_stats, "nclasses",
160 160 IPP_STAT_UINT32, &gblsnames->nclasses)) != 0) {
161 161 return (rc);
162 162 }
163 163 if ((rc = ipp_stat_named_init(ipgpc_global_stats, "nbytes",
164 164 IPP_STAT_UINT64, &gblsnames->nbytes)) != 0) {
165 165 return (rc);
166 166 }
167 167 if ((rc = ipp_stat_named_init(ipgpc_global_stats, "npackets",
168 168 IPP_STAT_UINT64, &gblsnames->npackets)) != 0) {
169 169 return (rc);
170 170 }
171 171 if ((rc = ipp_stat_named_init(ipgpc_global_stats, "epackets",
172 172 IPP_STAT_UINT64, &gblsnames->epackets)) != 0) {
173 173 return (rc);
174 174 }
175 175 ipp_stat_install(ipgpc_global_stats);
176 176 return (0);
177 177 }
178 178
179 179 static void
180 180 insert_ipgpc_trie_list_info(int trie_id, size_t key_len, trie in_trie,
181 181 uint16_t mask)
182 182 {
183 183 ipgpc_trie_list[trie_id].trie = in_trie;
184 184 rw_init(&ipgpc_trie_list[trie_id].rw_lock, NULL, RW_DEFAULT, NULL);
185 185 ipgpc_trie_list[trie_id].key_len = key_len;
186 186 ipgpc_trie_list[trie_id].info.mask = mask;
187 187 ipgpc_trie_list[trie_id].info.dontcareonly = B_TRUE;
188 188 }
189 189
190 190 static int
191 191 initialize_tries(void)
192 192 {
193 193 /* IPv4 Source Address field structure */
194 194 if ((saddr_trie = create_node(KM_NOSLEEP)) == NULL) {
195 195 return (ENOMEM);
196 196 }
197 197 saddr_trie->isroot = 1;
198 198 insert_ipgpc_trie_list_info(IPGPC_TRIE_SADDRID, IP_ABITS, saddr_trie,
199 199 SADDR_MASK);
200 200 /* IPv4 Destination Address field structure */
201 201 if ((daddr_trie = create_node(KM_NOSLEEP)) == NULL) {
202 202 return (ENOMEM);
203 203 }
204 204 daddr_trie->isroot = 1;
205 205 insert_ipgpc_trie_list_info(IPGPC_TRIE_DADDRID, IP_ABITS, daddr_trie,
206 206 DADDR_MASK);
207 207 /* TCP Source Port field structure */
208 208 if ((sport_trie = create_node(KM_NOSLEEP)) == NULL) {
209 209 return (ENOMEM);
210 210 }
211 211 sport_trie->isroot = 1;
212 212 insert_ipgpc_trie_list_info(IPGPC_TRIE_SPORTID, BITLENGTH(uint16_t),
213 213 sport_trie, SPORT_MASK);
214 214 /* TCP Destination Port field structure */
215 215 if ((dport_trie = create_node(KM_NOSLEEP)) == NULL) {
216 216 return (ENOMEM);
217 217 }
218 218 dport_trie->isroot = 1;
219 219 insert_ipgpc_trie_list_info(IPGPC_TRIE_DPORTID, BITLENGTH(uint16_t),
220 220 dport_trie, DPORT_MASK);
221 221 /* IPv6 Source Address field structure */
222 222 if ((saddr6_trie = create_node(KM_NOSLEEP)) == NULL) {
223 223 return (ENOMEM);
224 224 }
225 225 saddr6_trie->isroot = 1;
226 226 insert_ipgpc_trie_list_info(IPGPC_TRIE_SADDRID6, IPV6_ABITS,
227 227 saddr6_trie, SADDR6_MASK);
228 228 /* IPv6 Destination Address field structure */
229 229 if ((daddr6_trie = create_node(KM_NOSLEEP)) == NULL) {
230 230 return (ENOMEM);
231 231 }
232 232 daddr6_trie->isroot = 1;
233 233 insert_ipgpc_trie_list_info(IPGPC_TRIE_DADDRID6, IPV6_ABITS,
234 234 daddr6_trie, DADDR6_MASK);
235 235 return (0);
236 236 }
237 237
238 238 static void
239 239 insert_ipgpc_table_list_info(int table_id, hash_table table, int wildcard,
240 240 uint16_t mask)
241 241 {
242 242 ipgpc_table_list[table_id].table = table;
243 243 ipgpc_table_list[table_id].wildcard = wildcard;
244 244 ipgpc_table_list[table_id].info.mask = mask;
245 245 ipgpc_table_list[table_id].info.dontcareonly = B_TRUE;
246 246 }
247 247 static void
248 248 initialize_tables(void)
249 249 {
250 250 /* Protocol selector structure */
251 251 insert_ipgpc_table_list_info(PROTOID_IDX, proto_table,
252 252 IPGPC_UNSPECIFIED, PROTO_MASK);
253 253 /* UID selector structure */
254 254 insert_ipgpc_table_list_info(UID_IDX, uid_table, IPGPC_WILDCARD,
255 255 UID_MASK);
256 256 /* PROJID selector structure */
257 257 insert_ipgpc_table_list_info(PROJID_IDX, projid_table, IPGPC_WILDCARD,
258 258 PROJID_MASK);
259 259 /* IF_INDEX selector structure */
260 260 insert_ipgpc_table_list_info(IF_IDX, if_table, IPGPC_UNSPECIFIED,
261 261 IF_MASK);
262 262 /* DIR selector structure */
263 263 insert_ipgpc_table_list_info(DIR_IDX, dir_table, IPGPC_UNSPECIFIED,
264 264 DIR_MASK);
265 265 }
266 266
267 267 static void
↓ open down ↓ |
267 lines elided |
↑ open up ↑ |
268 268 initialize_ba_tables(void)
269 269 {
270 270 /* DS (ToS/Traffic Class) field structure */
271 271 ipgpc_ds_table_id.info.mask = DS_MASK;
272 272 ipgpc_ds_table_id.info.dontcareonly = B_TRUE;
273 273 }
274 274
275 275 static void
276 276 element_node_ref(element_node_t *element)
277 277 {
278 - atomic_add_32(&element->element_refcnt, 1);
278 + atomic_inc_32(&element->element_refcnt);
279 279 ASSERT(element->element_refcnt > 1);
280 280 }
281 281
282 282 static void
283 283 element_node_unref(element_node_t *element)
284 284 {
285 285 ASSERT(element->element_refcnt > 0);
286 - if (atomic_add_32_nv(&element->element_refcnt, -1) == 0) {
286 + if (atomic_dec_32_nv(&element->element_refcnt) == 0) {
287 287 kmem_cache_free(element_node_cache, element);
288 288 }
289 289 }
290 290
291 291 /* ARGSUSED1 */
292 292 static int
293 293 element_node_cache_constructor(void *buf, void *cdrarg, int kmflags)
294 294 {
295 295 element_node_t *node = buf;
296 296
297 297 node->element_ref = element_node_ref;
298 298 node->element_unref = element_node_unref;
299 299 return (0);
300 300 }
301 301
302 302 /* prime values to be used for hashing of filter and class tables */
303 303 #define IPGPC_PRIMES() {0, 0, 0, 5, 11, 23, 47, 89, 191, 383, 503, 761, \
304 304 1009, 1531, 2003, 2503, 3067, 3511, 4001, 5003, 6143, \
305 305 10007, 12281, 15013, 20011, 24571, 49139, 98299, \
306 306 100003, 196597, 393209, 786431, 1000003, 1251409, \
307 307 1572853, 3145721, 0}
308 308
309 309 /*
310 310 * ipgpc_initialize(in_aid)
311 311 *
312 312 * initializes locks, data structures, configuration variables used and
313 313 * sets globals. Will fail on memory or initialization error.
314 314 */
315 315 int
316 316 ipgpc_initialize(ipp_action_id_t in_aid)
317 317 {
318 318 ipgpc_class_t def_class;
319 319 int i;
320 320 int rc;
321 321 int sizes[] = IPGPC_PRIMES();
322 322
323 323 /* initialize globals */
324 324 ipgpc_aid = in_aid; /* store away action id for ipgpc */
325 325 ipgpc_num_fltrs = 0;
326 326 ipgpc_num_cls = 0;
327 327 ipgpc_npackets = 0;
328 328 ipgpc_nbytes = 0;
329 329 ipgpc_epackets = 0;
330 330
331 331 /* check for user tunable maximums (set in /etc/system) */
332 332 if (ipgpc_max_filters > 0) {
333 333 /* start with a reasonably small value to find closest prime */
334 334 for (i = 3; i < sizeof (sizes) / sizeof (*sizes) - 1; ++i) {
335 335 if (sizes[i] >= ipgpc_max_filters) {
336 336 break;
337 337 }
338 338 }
339 339 if (sizes[i] == 0) {
340 340 ipgpc0dbg(("ipgpc_initialize: ipgpc_max_filters " \
341 341 "out of range"));
342 342 /* use the largest allowable value */
343 343 ipgpc_max_num_filters = sizes[(i - 1)];
344 344 } else {
345 345 ipgpc_max_num_filters = sizes[i];
346 346 }
347 347 }
348 348 if (ipgpc_max_classes > 0) {
349 349 /* start with a reasonably small value to find closest prime */
350 350 for (i = 3; i < sizeof (sizes) / sizeof (*sizes) - 1; ++i) {
351 351 if (sizes[i] >= ipgpc_max_classes) {
352 352 break;
353 353 }
354 354 }
355 355 if (sizes[i] == 0) {
356 356 ipgpc0dbg(("ipgpc_initialize: ipgpc_max_classes " \
357 357 "out of range"));
358 358 /* use the largest allowable value */
359 359 ipgpc_max_num_classes = sizes[(i - 1)];
360 360 } else {
361 361 ipgpc_max_num_classes = sizes[i];
362 362 }
363 363 }
364 364
365 365 /* create filter id list */
366 366 ipgpc_fid_list =
367 367 kmem_zalloc(sizeof (fid_t) * ipgpc_max_num_filters, KM_NOSLEEP);
368 368 if (ipgpc_fid_list == NULL) {
369 369 ipgpc0dbg(("ipgpc_initialize: failed to create fid list"));
370 370 return (ENOMEM);
371 371 }
372 372
373 373 /* create class id list */
374 374 ipgpc_cid_list = kmem_zalloc(sizeof (cid_t) * ipgpc_max_num_classes,
375 375 KM_NOSLEEP);
376 376 if (ipgpc_cid_list == NULL) {
377 377 ipgpc0dbg(("ipgpc_initialize: failed to create cid list"));
378 378 return (ENOMEM);
379 379 }
380 380
381 381 /* create object caches */
382 382 element_node_cache = kmem_cache_create("element_node_cache",
383 383 sizeof (element_node_t), 0, element_node_cache_constructor,
384 384 NULL, NULL, NULL, NULL, 0);
385 385 trie_node_cache = kmem_cache_create("trie_node_cache",
386 386 sizeof (node_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
387 387 ht_node_cache = kmem_cache_create("ht_node_cache",
388 388 sizeof (ht_node_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
389 389 ht_match_cache = kmem_cache_create("ht_match_cache",
390 390 sizeof (ht_match_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
391 391
392 392 /* initialize tries, catch memory errors */
393 393 if ((rc = initialize_tries()) != 0) {
394 394 return (rc);
395 395 }
396 396
397 397 initialize_tables(); /* no memory is allocated here */
398 398 initialize_ba_tables(); /* no memory is allocated here */
399 399
400 400 if ((rc = global_statinit()) != 0) { /* init global stats */
401 401 ipgpc0dbg(("ipgpc_initialize: global_statinit error " \
402 402 "%d", rc));
403 403 return (rc);
404 404 }
405 405
406 406 /* create default class */
407 407 bzero(&def_class, sizeof (ipgpc_class_t));
408 408 def_class.next_action = IPP_ACTION_CONT;
409 409 def_class.gather_stats = B_FALSE; /* don't gather stats by default */
410 410 (void) strcpy(def_class.class_name, "default");
411 411 def_class.originator = IPP_CONFIG_PERMANENT; /* label as permanent */
412 412
413 413 /* add default class and record default class id */
414 414 if ((rc = insertcid(&def_class, &ipgpc_def_class_id)) != ENOENT) {
415 415 ipgpc0dbg(("ipgpc_initialize: insert of default class failed" \
416 416 " with error %d", rc));
417 417 return (rc);
418 418 }
419 419 return (0);
420 420 }
421 421
422 422 /*
423 423 * Module modify code
424 424 */
425 425
426 426 /*
427 427 * name_hash(name, M)
428 428 *
429 429 * hash function for a string (name) of lenght M
430 430 */
431 431 unsigned
432 432 name_hash(char *name, size_t M)
433 433 {
434 434 unsigned h;
435 435
436 436 for (h = 0; *name != '\0'; name++) {
437 437 h = ((64 * h) + *name);
438 438 }
439 439 return ((h % M));
440 440 }
441 441
442 442
443 443 /*
444 444 * ipgpc_filter_destructor(filter)
445 445 *
446 446 * frees any allocated memory pointed to in the filter structure
447 447 * this function should be run before freeing an ipgpc_filter_t
448 448 */
449 449 void
450 450 ipgpc_filter_destructor(ipgpc_filter_t *filter)
451 451 {
452 452 if (filter->filter_comment != NULL) {
453 453 kmem_free(filter->filter_comment,
454 454 (strlen(filter->filter_comment) + 1));
455 455 }
456 456 if (filter->saddr_hostname != NULL) {
457 457 kmem_free(filter->saddr_hostname,
458 458 (strlen(filter->saddr_hostname) + 1));
459 459 }
460 460 if (filter->daddr_hostname != NULL) {
461 461 kmem_free(filter->daddr_hostname,
462 462 (strlen(filter->daddr_hostname) + 1));
463 463 }
464 464 }
465 465
466 466 /*
467 467 * filter_name2id(*out_id, name, filter_instance, in_num_filters)
468 468 *
469 469 * looks up name and instance in filter id table
470 470 * checks in_num_filters against max filter boundary
471 471 * if found, returns EEXIST and places the id in out_id
472 472 * if not found, returns ENOENT and places the new id in out_id
473 473 * if no additional filter ids are available, ENOMEM is returned
474 474 */
475 475 static int
476 476 filter_name2id(unsigned *out_id, char name[], int32_t filter_instance,
477 477 int in_num_filters)
478 478 {
479 479 unsigned h;
480 480 int dirty = -1; /* set dirty to not found */
481 481
482 482 if (in_num_filters >= ipgpc_max_num_filters) {
483 483 return (ENOSPC); /* will exceed maximum number of filters */
484 484 }
485 485
486 486 /*
487 487 * search until fid w/ matching name is found or clean space is found
488 488 * if clean space is found, return first dirty space found or if
489 489 * none werer found, return clean space
490 490 */
491 491 h = name_hash(name, ipgpc_max_num_filters);
492 492 while ((ipgpc_fid_list[h].info != 0) &&
493 493 ((ipgpc_fid_list[h].filter.filter_instance != filter_instance) ||
494 494 (strcmp(name, ipgpc_fid_list[h].filter.filter_name) != 0))) {
495 495 if (dirty == -1) { /* this is the first dirty space */
496 496 if (ipgpc_fid_list[h].info == -1) { /* dirty */
497 497 dirty = h;
498 498 }
499 499 }
500 500 h = (h + 1) % ipgpc_max_num_filters;
501 501 }
502 502 /*
503 503 * check to see if searching stopped because a clean spot was found
504 504 * and a dirty space was seen before
505 505 */
506 506 if ((dirty != -1) && (ipgpc_fid_list[h].info == 0)) {
507 507 *out_id = dirty;
508 508 return (ENOENT); /* name does not exist in table */
509 509 } else if (ipgpc_fid_list[h].info == 0) {
510 510 *out_id = h;
511 511 return (ENOENT); /* name does not exist in table */
512 512 } else {
513 513 *out_id = h;
514 514 if (ipgpc_fid_list[h].info == -1) {
515 515 return (ENOENT);
516 516 } else {
517 517 return (EEXIST); /* name exists in table */
518 518 }
519 519 }
520 520 }
521 521
522 522 /*
523 523 * class_name2id(*out_id, name, in_num_classes)
524 524 *
525 525 * looks up name in class id table
526 526 * checks in_num_classes against max class boundry
527 527 * if found, returns EEXIST and places the id in out_id
528 528 * if not found, returns ENOENT and places the new id in out_id
529 529 * if no additional class ids are available, ENOSPC is returned
530 530 */
531 531 static int
532 532 class_name2id(unsigned *out_id, char name[], int in_num_classes)
533 533 {
534 534 unsigned h;
535 535 int dirty = -1; /* set dirty to not found */
536 536
537 537 if (in_num_classes >= ipgpc_max_num_classes) {
538 538 return (ENOSPC); /* will exceed maximum number of classes */
539 539 }
540 540
541 541 /*
542 542 * search until cid w/ matching name is found or clean space is found
543 543 * if clean space is found, return first dirty space found or if
544 544 * none were found, return clean space
545 545 */
546 546 h = name_hash(name, ipgpc_max_num_classes);
547 547 while ((ipgpc_cid_list[h].info != 0) &&
548 548 (strcmp(name, ipgpc_cid_list[h].aclass.class_name) != 0)) {
549 549 if (dirty == -1) { /* this is the first dirty space */
550 550 if (ipgpc_cid_list[h].info == -1) { /* dirty */
551 551 dirty = h;
552 552 }
553 553 }
554 554 h = (h + 1) % ipgpc_max_num_classes;
555 555 }
556 556 /*
557 557 * check to see if searching stopped because a clean spot was found
558 558 * and a dirty space was seen before
559 559 */
560 560 if ((dirty != -1) && (ipgpc_cid_list[h].info == 0)) {
561 561 *out_id = dirty;
562 562 return (ENOENT); /* name does not exist in table */
563 563 } else if (ipgpc_cid_list[h].info == 0) {
564 564 *out_id = h;
565 565 return (ENOENT); /* name does not exist in table */
566 566 } else {
567 567 *out_id = h;
568 568 if (ipgpc_cid_list[h].info == -1) { /* name did exist */
569 569 return (ENOENT); /* name does not exist in table */
570 570 } else {
571 571 return (EEXIST); /* name exists in table */
572 572 }
573 573 }
574 574 }
575 575
576 576 /*
577 577 * ipgpc_parse_filter(filter, nvlp)
578 578 *
579 579 * given a name value pair list, a filter structure is parsed. A valid
580 580 * filter must have a filter_name and originator id. Any value that is not
581 581 * present, will be given the default wildcard value for that selector
582 582 */
583 583 int
584 584 ipgpc_parse_filter(ipgpc_filter_t *filter, nvlist_t *nvlp)
585 585 {
586 586 uint_t nelem = 4; /* an IPv6 address is an uint32_t array[4] */
587 587 uint32_t *mask;
588 588 uint32_t *addr;
589 589 char *s;
590 590 int i;
591 591 in6_addr_t zeroaddr = IN6ADDR_ANY_INIT;
592 592
593 593 /* parse filter name */
594 594 if (nvlist_lookup_string(nvlp, CLASSIFIER_FILTER_NAME, &s) != 0) {
595 595 return (EINVAL); /* filter name is missing, error */
596 596 }
597 597
598 598 /* parse originator */
599 599 if (nvlist_lookup_uint32(nvlp, IPP_CONFIG_ORIGINATOR,
600 600 &filter->originator) != 0) {
601 601 ipgpc0dbg(("ipgpc_parse_filter: originator missing"));
602 602 return (EINVAL);
603 603 }
604 604
605 605 /* check for max name length */
606 606 if ((strlen(s) + 1) > MAXNAMELEN) {
607 607 ipgpc0dbg(("ipgpc_parse_filter: filter name length > " \
608 608 "MAXNAMELEN"));
609 609 return (EINVAL);
610 610 }
611 611
612 612 bcopy(s, filter->filter_name, (strlen(s) + 1));
613 613
614 614 /* parse uid */
615 615 if (nvlist_lookup_uint32(nvlp, IPGPC_UID, &filter->uid) != 0) {
616 616 filter->uid = (uid_t)IPGPC_WILDCARD;
617 617 }
618 618
619 619 /* parse projid */
620 620 if (nvlist_lookup_int32(nvlp, IPGPC_PROJID, &filter->projid) != 0) {
621 621 filter->projid = IPGPC_WILDCARD;
622 622 }
623 623
624 624 /* parse if_index */
625 625 if (nvlist_lookup_uint32(nvlp, IPGPC_IF_INDEX, &filter->if_index)
626 626 != 0) {
627 627 filter->if_index = 0;
628 628 }
629 629
630 630 /* parse direction */
631 631 if (nvlist_lookup_uint32(nvlp, IPGPC_DIR, &filter->direction) != 0) {
632 632 filter->direction = 0;
633 633 }
634 634
635 635 /* parse proto */
636 636 if (nvlist_lookup_byte(nvlp, IPGPC_PROTO, &filter->proto) != 0) {
637 637 filter->proto = 0;
638 638 }
639 639
640 640 /*
641 641 * parse dsfield mask, if mask is present and dsfield value is not,
642 642 * then this is an invalid filter configuration
643 643 */
644 644 if (nvlist_lookup_byte(nvlp, IPGPC_DSFIELD_MASK, &filter->dsfield_mask)
645 645 == 0) {
646 646 /* parse dsfield */
647 647 if (nvlist_lookup_byte(nvlp, IPGPC_DSFIELD, &filter->dsfield)
648 648 != 0) {
649 649 ipgpc0dbg(("ipgpc_parse_filter: dsfield missing" \
650 650 " when dsfield_mask 0x%x is present",
651 651 filter->dsfield_mask));
652 652 return (EINVAL);
653 653 }
654 654 } else {
655 655 filter->dsfield_mask = 0;
656 656 /* check to see if user added dsfield, but not dsfield_mask */
657 657 if (nvlist_lookup_byte(nvlp, IPGPC_DSFIELD, &filter->dsfield)
658 658 == 0) {
659 659 ipgpc0dbg(("ipgpc_parse_filter: dsfield_mask missing" \
660 660 " when dsfield 0x%x is present",
661 661 filter->dsfield));
662 662 return (EINVAL);
663 663 }
664 664 filter->dsfield = 0;
665 665 }
666 666
667 667 /* parse source port */
668 668 if (nvlist_lookup_uint16(nvlp, IPGPC_SPORT, &filter->sport) != 0) {
669 669 filter->sport = 0;
670 670 }
671 671
672 672 /*
673 673 * parse source port mask, mask and value must be present, or neither
674 674 */
675 675 if (nvlist_lookup_uint16(nvlp, IPGPC_SPORT_MASK, &filter->sport_mask)
676 676 != 0) {
677 677 if (filter->sport != 0) {
678 678 ipgpc0dbg(("ipgpc_parse_filter: sport_mask missing " \
679 679 "to mask sport %u", filter->sport));
680 680 return (EINVAL);
681 681 }
682 682 filter->sport_mask = 0;
683 683 } else { /* sport mask is present */
684 684 if (filter->sport == 0) {
685 685 ipgpc0dbg(("ipgpc_parse_filter: sport missing " \
686 686 "when sport_mask %u is present",
687 687 filter->sport_mask));
688 688 return (EINVAL);
689 689 }
690 690 }
691 691
692 692 /* check for non-continuous mask */
693 693 if (!iscontinuousmask(filter->sport_mask, BITLENGTH(uint16_t))) {
694 694 ipgpc0dbg(("ipgpc_parse_filter: sport_mask is " \
695 695 "non-continuous"));
696 696 return (EINVAL);
697 697 }
698 698
699 699 /* parse destination port */
700 700 if (nvlist_lookup_uint16(nvlp, IPGPC_DPORT, &filter->dport) != 0) {
701 701 filter->dport = 0;
702 702 }
703 703
704 704 /*
705 705 * parse destination port mask, mask and value must be present,
706 706 * or neither
707 707 */
708 708 if (nvlist_lookup_uint16(nvlp, IPGPC_DPORT_MASK, &filter->dport_mask)
709 709 != 0) {
710 710 if (filter->dport != 0) {
711 711 ipgpc0dbg(("ipgpc_parse_filter: dport_mask missing " \
712 712 "to mask dport %u", filter->dport));
713 713 return (EINVAL);
714 714 }
715 715 filter->dport_mask = 0;
716 716 } else { /* dport mask is present */
717 717 if (filter->dport == 0) {
718 718 ipgpc0dbg(("ipgpc_parse_filter: dport missing " \
719 719 "when dport_mask %u is present",
720 720 filter->dport_mask));
721 721 return (EINVAL);
722 722 }
723 723 }
724 724
725 725 /* check for non-continuous mask */
726 726 if (!iscontinuousmask(filter->dport_mask, BITLENGTH(uint16_t))) {
727 727 ipgpc0dbg(("ipgpc_parse_filter: dport_mask is " \
728 728 "non-continuous"));
729 729 return (EINVAL);
730 730 }
731 731
732 732 /* parse precedence */
733 733 if (nvlist_lookup_uint32(nvlp, IPGPC_PRECEDENCE, &filter->precedence)
734 734 != 0) {
735 735 filter->precedence = UINT_MAX; /* worst precedence */
736 736 }
737 737
738 738 /* parse priority */
739 739 if (nvlist_lookup_uint32(nvlp, IPGPC_PRIORITY, &filter->priority)
740 740 != 0) {
741 741 filter->priority = 0; /* worst priority */
742 742 }
743 743
744 744 /* parse filter type */
745 745 if (nvlist_lookup_byte(nvlp, IPGPC_FILTER_TYPE, &filter->filter_type)
746 746 != 0) {
747 747 filter->filter_type = IPGPC_GENERIC_FLTR;
748 748 }
749 749
750 750 /* parse filter instance */
751 751 if (nvlist_lookup_int32(nvlp, IPGPC_FILTER_INSTANCE,
752 752 &filter->filter_instance) != 0) {
753 753 filter->filter_instance = -1;
754 754 }
755 755
756 756 /* parse filter private field */
757 757 if (nvlist_lookup_string(nvlp, IPGPC_FILTER_PRIVATE, &s) != 0) {
758 758 filter->filter_comment = NULL;
759 759 } else {
760 760 filter->filter_comment = kmem_alloc((strlen(s) + 1), KM_SLEEP);
761 761 (void) strcpy(filter->filter_comment, s);
762 762 }
763 763
764 764 /*
765 765 * parse source address mask, if address is present, mask must be
766 766 * present
767 767 */
768 768 if (nvlist_lookup_uint32_array(nvlp, IPGPC_SADDR_MASK, &mask, &nelem)
769 769 != 0) {
770 770 /* check if source address is present */
771 771 if (nvlist_lookup_uint32_array(nvlp, IPGPC_SADDR, &addr,
772 772 &nelem) == 0) {
773 773 ipgpc0dbg(("ipgpc_parse_filter: source address mask " \
774 774 "missing"));
775 775 return (EINVAL);
776 776 } else { /* both saddr and saddr_mask absent */
777 777 bcopy(zeroaddr.s6_addr32, filter->saddr.s6_addr32,
778 778 sizeof (filter->saddr.s6_addr32));
779 779 }
780 780 bcopy(zeroaddr.s6_addr32, filter->saddr_mask.s6_addr32,
781 781 sizeof (filter->saddr_mask.s6_addr32));
782 782 } else { /* saddr_mask present */
783 783 /* parse source address */
784 784 if (nvlist_lookup_uint32_array(nvlp, IPGPC_SADDR, &addr,
785 785 &nelem) != 0) {
786 786 ipgpc0dbg(("ipgpc_parse_filter: source address " \
787 787 "missing"));
788 788 return (EINVAL);
789 789 } else { /* saddr present */
790 790 bcopy(addr, filter->saddr.s6_addr32,
791 791 sizeof (filter->saddr.s6_addr32));
792 792 }
793 793 bcopy(mask, filter->saddr_mask.s6_addr32,
794 794 sizeof (filter->saddr_mask.s6_addr32));
795 795 }
796 796
797 797 /* check for non-continuous mask */
798 798 if ((filter->filter_type == IPGPC_V6_FLTR) ||
799 799 (filter->filter_type == IPGPC_GENERIC_FLTR)) {
800 800 boolean_t zero_found = B_FALSE;
801 801 for (i = 0; i < 4; ++i) {
802 802 if (filter->saddr_mask.s6_addr32[i] == 0) {
803 803 zero_found = B_TRUE;
804 804 } else {
805 805 if (zero_found) {
806 806 ipgpc0dbg(("ipgpc_parse_filter: "
807 807 "saddr_mask is non-continuous"));
808 808 return (EINVAL);
809 809 }
810 810 }
811 811 if (!iscontinuousmask(filter->saddr_mask.s6_addr32[i],
812 812 IP_ABITS)) {
813 813 ipgpc0dbg(("ipgpc_parse_filter: saddr_mask " \
814 814 "is non-continuous"));
815 815 return (EINVAL);
816 816 }
817 817 }
818 818 } else { /* IPGPC_V4_FLTR */
819 819 if (!iscontinuousmask((V4_PART_OF_V6(filter->saddr_mask)),
820 820 IP_ABITS)) {
821 821 ipgpc0dbg(("ipgpc_parse_filter: saddr_mask is " \
822 822 "non-continuous"));
823 823 return (EINVAL);
824 824 }
825 825 }
826 826
827 827 /* parse source address hostname */
828 828 if (nvlist_lookup_string(nvlp, IPGPC_SADDR_HOSTNAME, &s) != 0) {
829 829 filter->saddr_hostname = NULL;
830 830 } else {
831 831 filter->saddr_hostname = kmem_alloc((strlen(s) + 1), KM_SLEEP);
832 832 (void) strcpy(filter->saddr_hostname, s);
833 833 }
834 834
835 835 /*
836 836 * parse destination address mask, if address is present, mask must be
837 837 * present
838 838 */
839 839 if (nvlist_lookup_uint32_array(nvlp, IPGPC_DADDR_MASK, &mask, &nelem)
840 840 != 0) {
841 841 /* check if destination address is present */
842 842 if (nvlist_lookup_uint32_array(nvlp, IPGPC_DADDR, &addr,
843 843 &nelem) == 0) {
844 844 ipgpc0dbg(("ipgpc_parse_filter: destination address " \
845 845 "mask missing"));
846 846 return (EINVAL);
847 847 } else { /* both daddr and daddr_mask absent */
848 848 bcopy(zeroaddr.s6_addr32, filter->daddr.s6_addr32,
849 849 sizeof (filter->daddr.s6_addr32));
850 850 }
851 851 bcopy(zeroaddr.s6_addr32, filter->daddr_mask.s6_addr32,
852 852 sizeof (filter->daddr_mask.s6_addr32));
853 853 } else { /* daddr_mask present */
854 854 /* parse destination address */
855 855 if (nvlist_lookup_uint32_array(nvlp, IPGPC_DADDR, &addr,
856 856 &nelem) != 0) {
857 857 ipgpc0dbg(("ipgpc_parse_filter: destination address " \
858 858 "missing"));
859 859 return (EINVAL);
860 860 } else { /* daddr present */
861 861 bcopy(addr, filter->daddr.s6_addr32,
862 862 sizeof (filter->daddr.s6_addr32));
863 863 }
864 864 bcopy(mask, filter->daddr_mask.s6_addr32,
865 865 sizeof (filter->daddr_mask.s6_addr32));
866 866 }
867 867
868 868 /* check for non-continuous mask */
869 869 if ((filter->filter_type == IPGPC_V6_FLTR) ||
870 870 (filter->filter_type == IPGPC_GENERIC_FLTR)) {
871 871 boolean_t zero_found = B_FALSE;
872 872 for (i = 0; i < 4; ++i) {
873 873 if (filter->daddr_mask.s6_addr32[i] == 0) {
874 874 zero_found = B_TRUE;
875 875 } else {
876 876 if (zero_found) {
877 877 ipgpc0dbg(("ipgpc_parse_filter: "
878 878 "daddr_mask is non-continuous"));
879 879 return (EINVAL);
880 880 }
881 881 }
882 882 if (!iscontinuousmask(filter->daddr_mask.s6_addr32[i],
883 883 IP_ABITS)) {
884 884 ipgpc0dbg(("ipgpc_parse_filter: daddr_mask " \
885 885 "is non-continuous"));
886 886 return (EINVAL);
887 887 }
888 888 }
889 889 } else { /* IPGPC_V4_FLTR */
890 890 if (!iscontinuousmask((V4_PART_OF_V6(filter->daddr_mask)),
891 891 IP_ABITS)) {
892 892 ipgpc0dbg(("ipgpc_parse_filter: daddr_mask is " \
893 893 "non-continuous"));
894 894 return (EINVAL);
895 895 }
896 896 }
897 897
898 898 /* parse destination address hostname */
899 899 if (nvlist_lookup_string(nvlp, IPGPC_DADDR_HOSTNAME, &s) != 0) {
900 900 filter->daddr_hostname = NULL;
901 901 } else {
902 902 filter->daddr_hostname = kmem_alloc((strlen(s) + 1), KM_SLEEP);
903 903 (void) strcpy(filter->daddr_hostname, s);
904 904 }
905 905
906 906 return (0);
907 907 }
908 908
909 909 /*
910 910 * iscontinuousmask(mask, len)
911 911 *
912 912 * Searches a given mask of length len from MSB to LSB looking for a zero
913 913 * bit followed by one bit. A continuous mask must be a string of zero or
914 914 * more ones followed by a string of zero or more zeros, which would return
915 915 * B_TRUE. Otherwise, it is not continuous and this function returns B_FALSE.
916 916 */
917 917 static boolean_t
918 918 iscontinuousmask(uint32_t mask, uint8_t len)
919 919 {
920 920 uint8_t pos;
921 921 boolean_t zero_found = B_FALSE;
922 922
923 923 for (pos = len; pos > 0; --pos) {
924 924 if (EXTRACTBIT(mask, (pos - 1), len) == 0) {
925 925 zero_found = B_TRUE;
926 926 } else {
927 927 if (zero_found) {
928 928 return (B_FALSE);
929 929 }
930 930 }
931 931 }
932 932 return (B_TRUE);
933 933 }
934 934
935 935
936 936 /*
937 937 * insertfid(filter_id, filter, class_id)
938 938 *
939 939 * creates a filter id (fid) structure for filter with filter_id.
940 940 * filter is associated with the input class id
941 941 * it is assumed that a fid will not be inserted for a filter that already
942 942 * exists by the same name.
943 943 */
944 944 static void
945 945 insertfid(int filter_id, ipgpc_filter_t *filter, uint_t class_id)
946 946 {
947 947 ipgpc_fid_list[filter_id].info = 1;
948 948 ipgpc3dbg(("insert_fid: adding filter %s to class %s",
949 949 filter->filter_name,
950 950 ipgpc_cid_list[class_id].aclass.class_name));
951 951 ipgpc_fid_list[filter_id].class_id = class_id;
952 952 ipgpc_fid_list[filter_id].filter = *filter;
953 953 ipgpc_fid_list[filter_id].insert_map = 0;
954 954 }
955 955
956 956
957 957 static void
958 958 common_addfilter(fid_t *fid, int filter_id)
959 959 {
960 960 /* start trie inserts */
961 961 /* add source port selector */
962 962 if (t_insert(&ipgpc_trie_list[IPGPC_TRIE_SPORTID], filter_id,
963 963 fid->filter.sport, fid->filter.sport_mask) == NORMAL_VALUE) {
964 964 fid->insert_map |= SPORT_MASK;
965 965 }
966 966 /* add destination port selector */
967 967 if (t_insert(&ipgpc_trie_list[IPGPC_TRIE_DPORTID], filter_id,
968 968 fid->filter.dport, fid->filter.dport_mask) == NORMAL_VALUE) {
969 969 fid->insert_map |= DPORT_MASK;
970 970 }
971 971 /* end trie inserts */
972 972
973 973 /* add diffserv field selector */
974 974 mutex_enter(&ipgpc_ds_table_id.lock);
975 975 if (ba_insert(&ipgpc_ds_table_id, filter_id, fid->filter.dsfield,
976 976 fid->filter.dsfield_mask) == NORMAL_VALUE) {
977 977 fid->insert_map |= DS_MASK;
978 978 }
979 979 mutex_exit(&ipgpc_ds_table_id.lock);
980 980
981 981 /* start table inserts */
982 982 mutex_enter(&ipgpc_table_list_lock);
983 983 /* add protocol selector */
984 984 if (ht_insert(&ipgpc_table_list[PROTOID_IDX], filter_id,
985 985 fid->filter.proto) == NORMAL_VALUE) {
986 986 fid->insert_map |= PROTO_MASK;
987 987 }
988 988
989 989 /* add UID selector */
990 990 if (ht_insert(&ipgpc_table_list[UID_IDX], filter_id, fid->filter.uid)
991 991 == NORMAL_VALUE) {
992 992 fid->insert_map |= UID_MASK;
993 993 }
994 994
995 995 /* add PROJID selector */
996 996 if (ht_insert(&ipgpc_table_list[PROJID_IDX], filter_id,
997 997 fid->filter.projid) == NORMAL_VALUE) {
998 998 fid->insert_map |= PROJID_MASK;
999 999 }
1000 1000
1001 1001 /* add interface index selector */
1002 1002 if (ht_insert(&ipgpc_table_list[IF_IDX], filter_id,
1003 1003 fid->filter.if_index) == NORMAL_VALUE) {
1004 1004 fid->insert_map |= IF_MASK;
1005 1005 }
1006 1006
1007 1007 /* add direction selector */
1008 1008 if (ht_insert(&ipgpc_table_list[DIR_IDX], filter_id,
1009 1009 fid->filter.direction) == NORMAL_VALUE) {
1010 1010 fid->insert_map |= DIR_MASK;
1011 1011 }
1012 1012 mutex_exit(&ipgpc_table_list_lock);
1013 1013 /* end table inserts */
1014 1014 }
1015 1015
1016 1016 static void
1017 1017 v4_addfilter(fid_t *fid, int filter_id)
1018 1018 {
1019 1019 /* add IPv4 source address selector */
1020 1020 if (t_insert(&ipgpc_trie_list[IPGPC_TRIE_SADDRID], filter_id,
1021 1021 V4_PART_OF_V6(fid->filter.saddr),
1022 1022 V4_PART_OF_V6(fid->filter.saddr_mask)) == NORMAL_VALUE) {
1023 1023 fid->insert_map |= SADDR_MASK;
1024 1024 }
1025 1025
1026 1026 /* add IPv4 destination address selector */
1027 1027 if (t_insert(&ipgpc_trie_list[IPGPC_TRIE_DADDRID], filter_id,
1028 1028 V4_PART_OF_V6(fid->filter.daddr),
1029 1029 V4_PART_OF_V6(fid->filter.daddr_mask)) == NORMAL_VALUE) {
1030 1030 fid->insert_map |= DADDR_MASK;
1031 1031 }
1032 1032 }
1033 1033
1034 1034 static void
1035 1035 v6_addfilter(fid_t *fid, int filter_id)
1036 1036 {
1037 1037 /* add IPv6 source address selector */
1038 1038 if (t_insert6(&ipgpc_trie_list[IPGPC_TRIE_SADDRID6], filter_id,
1039 1039 fid->filter.saddr, fid->filter.saddr_mask) == NORMAL_VALUE) {
1040 1040 fid->insert_map |= SADDR6_MASK;
1041 1041 }
1042 1042
1043 1043 /* add IPv6 destination address selector */
1044 1044 if (t_insert6(&ipgpc_trie_list[IPGPC_TRIE_DADDRID6], filter_id,
1045 1045 fid->filter.daddr, fid->filter.daddr_mask) == NORMAL_VALUE) {
1046 1046 fid->insert_map |= DADDR6_MASK;
1047 1047 }
1048 1048 }
1049 1049
1050 1050 /*
1051 1051 * ipgpc_addfilter(filter, class_name, flags)
1052 1052 *
1053 1053 * add the specified filter and associate it with the specified class
1054 1054 * name
1055 1055 * - add filter id to filter list
1056 1056 * - add filter keys to selector structures
1057 1057 * - ENOENT is returned if class does not exist
1058 1058 * - EEXIST is returned if add failed because filter name exists
1059 1059 * - ENOMEM is returned if no memory is available to add a new filter
1060 1060 * - EINVAL if filter.filter_type is invalid
1061 1061 * - 0 is returned on success
1062 1062 * flags is unused currently
1063 1063 */
1064 1064 /* ARGSUSED1 */
1065 1065 int
1066 1066 ipgpc_addfilter(ipgpc_filter_t *filter, char *class_name, ipp_flags_t flags)
1067 1067 {
1068 1068 unsigned filter_id;
1069 1069 int err = 0;
1070 1070 fid_t *fid;
1071 1071 unsigned class_id;
1072 1072
1073 1073 err = class_name2id(&class_id, class_name, ipgpc_num_cls);
1074 1074 if (err != EEXIST) {
1075 1075 ipgpc0dbg(("ipgpc_addfilter: class lookup error %d", err));
1076 1076 return (err);
1077 1077 }
1078 1078 mutex_enter(&ipgpc_fid_list_lock);
1079 1079 /* make sure filter does not already exist */
1080 1080 if ((err = filter_name2id(&filter_id, filter->filter_name,
1081 1081 filter->filter_instance, ipgpc_num_fltrs + 1)) == EEXIST) {
1082 1082 ipgpc0dbg(("ipgpc_addfilter: filter name %s already exists",
1083 1083 filter->filter_name));
1084 1084 mutex_exit(&ipgpc_fid_list_lock);
1085 1085 return (err);
1086 1086 } else if (err == ENOSPC) {
1087 1087 ipgpc0dbg(("ipgpc_addfilter: can not add filter %s, " \
1088 1088 "ipgpc_max_num_filteres has been reached",
1089 1089 filter->filter_name));
1090 1090 mutex_exit(&ipgpc_fid_list_lock);
1091 1091 return (err);
1092 1092 }
1093 1093 insertfid(filter_id, filter, class_id);
1094 1094
1095 1095 fid = &ipgpc_fid_list[filter_id];
1096 1096 /* add filter id to selector structures */
1097 1097 switch (fid->filter.filter_type) {
1098 1098 case IPGPC_GENERIC_FLTR:
1099 1099 /* add filter id to all selectors */
1100 1100 common_addfilter(fid, filter_id);
1101 1101 v4_addfilter(fid, filter_id);
1102 1102 v6_addfilter(fid, filter_id);
1103 1103 break;
1104 1104 case IPGPC_V4_FLTR:
1105 1105 /* add filter to common and V4 selectors */
1106 1106 common_addfilter(fid, filter_id);
1107 1107 v4_addfilter(fid, filter_id);
1108 1108 break;
1109 1109 case IPGPC_V6_FLTR:
1110 1110 /* add filter to common and V6 selectors */
1111 1111 common_addfilter(fid, filter_id);
1112 1112 v6_addfilter(fid, filter_id);
1113 1113 break;
1114 1114 default:
1115 1115 ipgpc0dbg(("ipgpc_addfilter(): invalid filter type %d",
1116 1116 fid->filter.filter_type));
1117 1117 mutex_exit(&ipgpc_fid_list_lock);
1118 1118 return (EINVAL);
1119 1119 }
1120 1120 /* check to see if this is a catch all filter, which we reject */
1121 1121 if (fid->insert_map == 0) {
1122 1122 ipgpc0dbg(("ipgpc_addfilter(): filter %s rejected because " \
1123 1123 "catch all filters are not supported\n",
1124 1124 filter->filter_name));
1125 1125 /* cleanup what we allocated */
1126 1126 /* remove filter from filter list */
1127 1127 ipgpc_fid_list[filter_id].info = -1;
1128 1128 ipgpc_fid_list[filter_id].filter.filter_name[0] = '\0';
↓ open down ↓ |
832 lines elided |
↑ open up ↑ |
1129 1129 reset_dontcare_stats(); /* need to fixup stats */
1130 1130 mutex_exit(&ipgpc_fid_list_lock);
1131 1131 return (EINVAL);
1132 1132 } else { /* associate filter with class */
1133 1133 mutex_enter(&ipgpc_cid_list_lock);
1134 1134 (void) ipgpc_list_insert(&ipgpc_cid_list[class_id].filter_list,
1135 1135 filter_id);
1136 1136 mutex_exit(&ipgpc_cid_list_lock);
1137 1137 }
1138 1138 mutex_exit(&ipgpc_fid_list_lock);
1139 - atomic_add_long(&ipgpc_num_fltrs, 1);
1139 + atomic_inc_ulong(&ipgpc_num_fltrs);
1140 1140 ipgpc3dbg(("ipgpc_addfilter: adding filter %s", filter->filter_name));
1141 1141 return (0);
1142 1142 }
1143 1143
1144 1144 /*
1145 1145 * reset_dontcare_stats()
1146 1146 *
1147 1147 * when an insertion fails because zero selectors are specified in a filter
1148 1148 * the number of dontcare's recorded for each selector structure needs to be
1149 1149 * decremented
1150 1150 */
1151 1151 static void
1152 1152 reset_dontcare_stats(void)
1153 1153 {
1154 1154 int i;
1155 1155
1156 1156 for (i = 0; i < NUM_TRIES; ++i) {
1157 - atomic_add_32(&ipgpc_trie_list[i].stats.num_dontcare, -1);
1157 + atomic_dec_32(&ipgpc_trie_list[i].stats.num_dontcare);
1158 1158 }
1159 1159 for (i = 0; i < NUM_TABLES; ++i) {
1160 - atomic_add_32(&ipgpc_table_list[i].stats.num_dontcare, -1);
1160 + atomic_dec_32(&ipgpc_table_list[i].stats.num_dontcare);
1161 1161 }
1162 - atomic_add_32(&ipgpc_ds_table_id.stats.num_dontcare, -1);
1162 + atomic_dec_32(&ipgpc_ds_table_id.stats.num_dontcare);
1163 1163 }
1164 1164
1165 1165 /*
1166 1166 * ipgpc_parse_class(out_class, nvlp)
1167 1167 *
1168 1168 * Given a name value pair list, a class structure will be parsed.
1169 1169 * To be a valid class, the class name, originator id and next action name
1170 1170 * must be present. gather_stats is optional, if absent default value is used
1171 1171 */
1172 1172 int
1173 1173 ipgpc_parse_class(ipgpc_class_t *out_class, nvlist_t *nvlp)
1174 1174 {
1175 1175 char *name;
1176 1176 size_t name_len;
1177 1177 uint32_t gather_stats;
1178 1178
1179 1179 /* parse class name */
1180 1180 if (nvlist_lookup_string(nvlp, CLASSIFIER_CLASS_NAME, &name) != 0) {
1181 1181 return (EINVAL); /* class name missing, error */
1182 1182 }
1183 1183
1184 1184 name_len = strlen(name);
1185 1185 /* check for max name length */
1186 1186 if ((name_len + 1) > MAXNAMELEN) {
1187 1187 ipgpc0dbg(("ipgpc_parse_class: class name length > " \
1188 1188 "MAXNAMELEN"));
1189 1189 return (EINVAL);
1190 1190 }
1191 1191
1192 1192 bcopy(name, out_class->class_name, (name_len + 1));
1193 1193
1194 1194 /* parse originator */
1195 1195 if (nvlist_lookup_uint32(nvlp, IPP_CONFIG_ORIGINATOR,
1196 1196 &out_class->originator) != 0) {
1197 1197 ipgpc0dbg(("ipgpc_parse_class: originator missing"));
1198 1198 return (EINVAL);
1199 1199 }
1200 1200
1201 1201 /* parse action name */
1202 1202 if (nvlist_lookup_string(nvlp, CLASSIFIER_NEXT_ACTION, &name) != 0) {
1203 1203 return (EINVAL); /* action name missing, error */
1204 1204 }
1205 1205 if ((out_class->next_action = ipp_action_lookup(name))
1206 1206 == IPP_ACTION_INVAL) {
1207 1207 ipgpc0dbg(("ipgpc_parse_class: invalid action name %s", name));
1208 1208 return (EINVAL);
1209 1209 }
1210 1210
1211 1211 /* parse gather stats boolean */
1212 1212 if (nvlist_lookup_uint32(nvlp, CLASSIFIER_CLASS_STATS_ENABLE,
1213 1213 &gather_stats) != 0) {
1214 1214 /* stats turned off by default */
1215 1215 out_class->gather_stats = B_FALSE;
1216 1216 } else {
1217 1217 out_class->gather_stats = (boolean_t)gather_stats;
1218 1218 }
1219 1219 return (0);
1220 1220 }
1221 1221
1222 1222
1223 1223 /*
1224 1224 * ipgpc_addclass(in_class, flags)
1225 1225 *
1226 1226 * adds the given class to the class id list.
1227 1227 * - EEXIST is returned if class of same name already exists
1228 1228 * - ENOSPC if there is no more available memory to add class
1229 1229 * - 0 for success
1230 1230 * flags is currently unused
1231 1231 */
1232 1232 /* ARGSUSED */
1233 1233 int
1234 1234 ipgpc_addclass(ipgpc_class_t *in_class, ipp_flags_t flags) {
1235 1235 int class_id;
1236 1236 int err;
1237 1237
1238 1238 if ((err = insertcid(in_class, &class_id)) == EEXIST) {
1239 1239 ipgpc0dbg(("ipgpc_addclass: class name %s already exists",
1240 1240 in_class->class_name));
1241 1241 return (err);
1242 1242 } else if (err == ENOSPC) {
1243 1243 ipgpc0dbg(("ipgpc_addclass: can not add class %s, " \
1244 1244 "ipgpc_max_num_classes has been reached",
1245 1245 in_class->class_name));
1246 1246 return (err);
1247 1247 }
1248 1248 /* add reference to next action */
1249 1249 if ((err = ipp_action_ref(ipgpc_aid, in_class->next_action, 0)) != 0) {
1250 1250 /*
1251 1251 * the action id we want to reference must have been
1252 1252 * destroyed before we could reference it. remove class
1253 1253 * and fail.
1254 1254 */
1255 1255 removecid(class_id);
1256 1256 return (err);
1257 1257 }
1258 1258 return (0);
1259 1259 }
1260 1260
1261 1261
1262 1262
1263 1263 /*
1264 1264 * class_statinit(in_class, in_class_id)
1265 1265 *
1266 1266 * for the given class, create stats entries to record
1267 1267 * - next action id
1268 1268 * - number of bytes that matched this class
1269 1269 * - number of packets that matched this class
1270 1270 * - time in hrtime of last match for this class
1271 1271 * any failures are returned, zero on success
1272 1272 */
1273 1273 static int
1274 1274 class_statinit(ipgpc_class_t *in_class, int in_class_id)
1275 1275 {
1276 1276 int rc;
1277 1277 ipp_stat_t *ipp_cl_stats;
1278 1278 classstats_t *clsnames = NULL;
1279 1279
1280 1280 /* create stat structure */
1281 1281 if ((rc = ipp_stat_create(ipgpc_aid, in_class->class_name, 3,
1282 1282 update_class_stats, &ipgpc_cid_list[in_class_id].stats,
1283 1283 &ipp_cl_stats)) != 0) {
1284 1284 ipgpc0dbg(("class_statinit: error creating ipp_stat entry"));
1285 1285 return (rc);
1286 1286 }
1287 1287
1288 1288 ASSERT(ipp_cl_stats != NULL);
1289 1289 clsnames = (classstats_t *)ipp_cl_stats->ipps_data;
1290 1290 ASSERT(clsnames != NULL);
1291 1291
1292 1292 /* create stats entry */
1293 1293 bzero(&ipgpc_cid_list[in_class_id].stats,
1294 1294 sizeof (ipgpc_class_stats_t));
1295 1295
1296 1296 /* set next action id */
1297 1297 ipgpc_cid_list[in_class_id].stats.next_action =
1298 1298 ipgpc_cid_list[in_class_id].aclass.next_action;
1299 1299
1300 1300 if ((rc = ipp_stat_named_init(ipp_cl_stats, "nbytes",
1301 1301 IPP_STAT_UINT64, &clsnames->nbytes)) != 0) {
1302 1302 return (rc);
1303 1303 }
1304 1304 if ((rc = ipp_stat_named_init(ipp_cl_stats, "npackets",
1305 1305 IPP_STAT_UINT64, &clsnames->npackets)) != 0) {
1306 1306 return (rc);
1307 1307 }
1308 1308 if ((rc = ipp_stat_named_init(ipp_cl_stats, "last_match",
1309 1309 IPP_STAT_INT64, &clsnames->last_match)) != 0) {
1310 1310 return (rc);
1311 1311 }
1312 1312
1313 1313 /* make reference to kstat structure, for removal */
1314 1314 ipgpc_cid_list[in_class_id].cl_stats = ipp_cl_stats;
1315 1315 ipp_stat_install(ipp_cl_stats);
1316 1316 return (0);
1317 1317 }
1318 1318
1319 1319 /*
1320 1320 * insertcid(in_class, out_class_id)
1321 1321 *
1322 1322 * creates a class id (cid) structure for in_class, if in_class name
1323 1323 * does not exist already. id is associated with in_class. the internal
1324 1324 * id of the cid associated with in_class is returned in out_class_id
1325 1325 * - ENOENT is returned if in_class->class_name does not already exist
1326 1326 * - EEXIST is returned if in_class->class_name does already exist
1327 1327 * - ENOSPC is returned if by adding this class, the ipgpc_max_num_classes
1328 1328 * will be exceeded.
1329 1329 */
1330 1330 static int
1331 1331 insertcid(ipgpc_class_t *in_class, int *out_class_id)
1332 1332 {
1333 1333 int err, rc;
1334 1334 unsigned class_id;
1335 1335
1336 1336 mutex_enter(&ipgpc_cid_list_lock);
1337 1337 /* see if entry already exists for class */
1338 1338 if ((err = class_name2id(&class_id, in_class->class_name,
1339 1339 ipgpc_num_cls + 1)) == ENOENT) {
1340 1340 /* create new filter list for new class */
1341 1341 ipgpc_cid_list[class_id].info = 1;
1342 1342 ipgpc_cid_list[class_id].aclass = *in_class;
1343 1343 if (in_class->gather_stats == B_TRUE) {
1344 1344 /* init kstat entry */
1345 1345 if ((rc = class_statinit(in_class, class_id)) != 0) {
1346 1346 ipgpc_cid_list[class_id].info = -1;
1347 1347 ipgpc0dbg(("insertcid: "
1348 1348 "class_statinit failed with error %d", rc));
1349 1349 mutex_exit(&ipgpc_cid_list_lock);
↓ open down ↓ |
177 lines elided |
↑ open up ↑ |
1350 1350 return (rc);
1351 1351 }
1352 1352 } else {
1353 1353 ipgpc_cid_list[class_id].cl_stats = NULL;
1354 1354 }
1355 1355 ipgpc3dbg(("insertcid: adding class %s",
1356 1356 in_class->class_name));
1357 1357 bcopy(in_class->class_name,
1358 1358 ipgpc_cid_list[class_id].aclass.class_name, MAXNAMELEN);
1359 1359 ipgpc_cid_list[class_id].filter_list = NULL;
1360 - atomic_add_long(&ipgpc_num_cls, 1);
1360 + atomic_inc_ulong(&ipgpc_num_cls);
1361 1361 } else {
1362 1362 ipgpc0dbg(("insertcid: class name lookup error %d", err));
1363 1363 mutex_exit(&ipgpc_cid_list_lock);
1364 1364 return (err);
1365 1365 }
1366 1366 mutex_exit(&ipgpc_cid_list_lock);
1367 1367 *out_class_id = class_id;
1368 1368 return (err);
1369 1369 }
1370 1370
1371 1371 /*
1372 1372 * common_removefilter(in_filter_id, fid)
1373 1373 *
1374 1374 * removes in_filter_id from each of the common selector structures
1375 1375 */
1376 1376 static void
1377 1377 common_removefilter(int in_filter_id, fid_t *fid)
1378 1378 {
1379 1379 /* start trie removes */
1380 1380 t_remove(&ipgpc_trie_list[IPGPC_TRIE_SPORTID], in_filter_id,
1381 1381 fid->filter.sport, fid->filter.sport_mask);
1382 1382 /* remove id from destination port trie */
1383 1383 t_remove(&ipgpc_trie_list[IPGPC_TRIE_DPORTID], in_filter_id,
1384 1384 fid->filter.dport, fid->filter.dport_mask);
1385 1385 /* end trie revmoves */
1386 1386
1387 1387 /* remove id from DiffServ field ba table */
1388 1388 mutex_enter(&ipgpc_ds_table_id.lock);
1389 1389 ba_remove(&ipgpc_ds_table_id, in_filter_id, fid->filter.dsfield,
1390 1390 fid->filter.dsfield_mask);
1391 1391 mutex_exit(&ipgpc_ds_table_id.lock);
1392 1392
1393 1393 /* start table removes */
1394 1394 mutex_enter(&ipgpc_table_list_lock);
1395 1395 /* remove id from protocol table */
1396 1396 ht_remove(&ipgpc_table_list[PROTOID_IDX], in_filter_id,
1397 1397 fid->filter.proto);
1398 1398 /* remove id from UID table */
1399 1399 ht_remove(&ipgpc_table_list[UID_IDX], in_filter_id, fid->filter.uid);
1400 1400 /* remove id from PROJID table */
1401 1401 ht_remove(&ipgpc_table_list[PROJID_IDX], in_filter_id,
1402 1402 fid->filter.projid);
1403 1403 /* remove id from interface id table */
1404 1404 ht_remove(&ipgpc_table_list[IF_IDX], in_filter_id,
1405 1405 fid->filter.if_index);
1406 1406 /* remove id from direction table */
1407 1407 ht_remove(&ipgpc_table_list[DIR_IDX], in_filter_id,
1408 1408 fid->filter.direction);
1409 1409 mutex_exit(&ipgpc_table_list_lock);
1410 1410 /* end table removes */
1411 1411 }
1412 1412
1413 1413 /*
1414 1414 * v4_removefilter(in_filter_id, fid)
1415 1415 *
1416 1416 * removes id from IPV4 specific structures
1417 1417 */
1418 1418 static void
1419 1419 v4_removefilter(int in_filter_id, fid_t *fid)
1420 1420 {
1421 1421 /* remove id from source address trie */
1422 1422 t_remove(&ipgpc_trie_list[IPGPC_TRIE_SADDRID], in_filter_id,
1423 1423 V4_PART_OF_V6(fid->filter.saddr),
1424 1424 V4_PART_OF_V6(fid->filter.saddr_mask));
1425 1425 /* remove id from destination address trie */
1426 1426 t_remove(&ipgpc_trie_list[IPGPC_TRIE_DADDRID], in_filter_id,
1427 1427 V4_PART_OF_V6(fid->filter.daddr),
1428 1428 V4_PART_OF_V6(fid->filter.daddr_mask));
1429 1429 }
1430 1430
1431 1431 /*
1432 1432 * v6_removefilter(in_filter_id, fid)
1433 1433 *
1434 1434 * removes id from IPV6 specific structures
1435 1435 */
1436 1436 static void
1437 1437 v6_removefilter(int in_filter_id, fid_t *fid)
1438 1438 {
1439 1439 /* remove id from source address trie */
1440 1440 t_remove6(&ipgpc_trie_list[IPGPC_TRIE_SADDRID6], in_filter_id,
1441 1441 fid->filter.saddr, fid->filter.saddr_mask);
1442 1442 /* remove id from destination address trie */
1443 1443 t_remove6(&ipgpc_trie_list[IPGPC_TRIE_DADDRID6], in_filter_id,
1444 1444 fid->filter.daddr, fid->filter.daddr_mask);
1445 1445 }
1446 1446
1447 1447 /*
1448 1448 * ipgpc_removefilter(filter_name, filter_instance, flags)
1449 1449 *
1450 1450 * remove the filter associated with the specified name and instance
1451 1451 * - remove filter keys from all search tries
1452 1452 * - remove from filter id list
1453 1453 * - ENOENT is returned if filter name does not exist
1454 1454 * - returns 0 on success
1455 1455 */
1456 1456 /* ARGSUSED */
1457 1457 int
1458 1458 ipgpc_removefilter(char *filter_name, int32_t filter_instance,
1459 1459 ipp_flags_t flags)
1460 1460 {
1461 1461 unsigned filter_id;
1462 1462 fid_t *fid;
1463 1463 int rc;
1464 1464
1465 1465 /* check to see if any filters are loaded */
1466 1466 if (ipgpc_num_fltrs == 0) {
1467 1467 return (ENOENT);
1468 1468 }
1469 1469
1470 1470 mutex_enter(&ipgpc_fid_list_lock);
1471 1471 /* lookup filter name, only existing filters can be removed */
1472 1472 if ((rc = filter_name2id(&filter_id, filter_name, filter_instance,
1473 1473 ipgpc_num_fltrs)) != EEXIST) {
1474 1474 mutex_exit(&ipgpc_fid_list_lock);
1475 1475 return (rc);
1476 1476 }
1477 1477 fid = &ipgpc_fid_list[filter_id];
1478 1478 switch (fid->filter.filter_type) {
1479 1479 case IPGPC_GENERIC_FLTR:
1480 1480 common_removefilter(filter_id, fid);
1481 1481 v4_removefilter(filter_id, fid);
1482 1482 v6_removefilter(filter_id, fid);
1483 1483 break;
1484 1484 case IPGPC_V4_FLTR:
1485 1485 common_removefilter(filter_id, fid);
1486 1486 v4_removefilter(filter_id, fid);
1487 1487 break;
1488 1488 case IPGPC_V6_FLTR:
1489 1489 common_removefilter(filter_id, fid);
1490 1490 v6_removefilter(filter_id, fid);
1491 1491 break;
1492 1492 default:
1493 1493 ipgpc0dbg(("ipgpc_removefilter(): invalid filter type %d",
1494 1494 fid->filter.filter_type));
1495 1495 mutex_exit(&ipgpc_fid_list_lock);
1496 1496 return (EINVAL);
↓ open down ↓ |
126 lines elided |
↑ open up ↑ |
1497 1497 }
1498 1498 /* remove filter from filter list */
1499 1499 ipgpc_fid_list[filter_id].info = -1;
1500 1500 ipgpc_fid_list[filter_id].insert_map = 0;
1501 1501 ipgpc_fid_list[filter_id].filter.filter_name[0] = '\0';
1502 1502 ipgpc_filter_destructor(&ipgpc_fid_list[filter_id].filter);
1503 1503 mutex_exit(&ipgpc_fid_list_lock);
1504 1504 /* remove filter id from class' list of filters */
1505 1505 remove_from_cid_filter_list(ipgpc_fid_list[filter_id].class_id,
1506 1506 filter_id);
1507 - atomic_add_long(&ipgpc_num_fltrs, -1);
1507 + atomic_dec_ulong(&ipgpc_num_fltrs);
1508 1508 return (0);
1509 1509 }
1510 1510
1511 1511 /*
1512 1512 * removecid(in_class_id)
1513 1513 *
1514 1514 * removes the cid entry from the cid list and frees allocated structures
1515 1515 */
1516 1516 static void
1517 1517 removecid(int in_class_id)
1518 1518 {
1519 1519 ipgpc_cid_list[in_class_id].info = -1;
1520 1520 ipgpc_cid_list[in_class_id].aclass.class_name[0] = '\0';
1521 1521 ipgpc_cid_list[in_class_id].aclass.next_action = -1;
1522 1522 /* delete kstat entry */
1523 1523 if (ipgpc_cid_list[in_class_id].cl_stats != NULL) {
1524 1524 ipp_stat_destroy(ipgpc_cid_list[in_class_id].cl_stats);
1525 1525 ipgpc_cid_list[in_class_id].cl_stats = NULL;
1526 1526 }
1527 1527 /* decrement total number of classes loaded */
1528 - atomic_add_long(&ipgpc_num_cls, -1);
1528 + atomic_dec_ulong(&ipgpc_num_cls);
1529 1529 }
1530 1530
1531 1531 /*
1532 1532 * remove_from_cid_filter_list(in_class_id, in_filter_id)
1533 1533 *
1534 1534 * removes the input filter_id from the filter_list of the class associated
1535 1535 * with the input class_id
1536 1536 */
1537 1537 static void
1538 1538 remove_from_cid_filter_list(int in_class_id, int in_filter_id)
1539 1539 {
1540 1540 cid_t *cid = &ipgpc_cid_list[in_class_id];
1541 1541
1542 1542 if (cid->filter_list != NULL) {
1543 1543 (void) ipgpc_list_remove(&cid->filter_list, in_filter_id);
1544 1544 }
1545 1545 }
1546 1546
1547 1547 /*
1548 1548 * ipgpc_removeclass(class_name)
1549 1549 *
1550 1550 * removes a class and all the filters that point to it (ouch!)
1551 1551 * - returns 0 on success
1552 1552 * - ENOENT if class name does not exist
1553 1553 * - ENOTSUP if class name equals 'default'
1554 1554 */
1555 1555 int
1556 1556 ipgpc_removeclass(char *class_name, ipp_flags_t flags)
1557 1557 {
1558 1558 unsigned class_id;
1559 1559 element_node_t *anode = NULL;
1560 1560 element_node_t *tnode = NULL;
1561 1561 fid_t *fid = NULL;
1562 1562 ipp_action_id_t old_next_action;
1563 1563 int rc;
1564 1564
1565 1565 /* check to see if any classes are loaded */
1566 1566 if (ipgpc_num_cls == 0) {
1567 1567 return (ENOENT);
1568 1568 }
1569 1569
1570 1570 mutex_enter(&ipgpc_cid_list_lock); /* set lock */
1571 1571 /* lookup class name, only classes that exist can be removed */
1572 1572 if ((rc = class_name2id(&class_id, class_name, (ipgpc_num_cls - 1)))
1573 1573 != EEXIST) {
1574 1574 mutex_exit(&ipgpc_cid_list_lock); /* release lock */
1575 1575 return (rc);
1576 1576 }
1577 1577 if (class_id == ipgpc_def_class_id) {
1578 1578 ipgpc0dbg(("ipgpc_removeclass(): default class may not be " \
1579 1579 "removed"));
1580 1580 mutex_exit(&ipgpc_cid_list_lock); /* release lock */
1581 1581 return (ENOTSUP);
1582 1582 }
1583 1583
1584 1584 old_next_action = ipgpc_cid_list[class_id].aclass.next_action;
1585 1585 anode = ipgpc_cid_list[class_id].filter_list;
1586 1586 while (anode != NULL) {
1587 1587 fid = &ipgpc_fid_list[anode->id];
1588 1588 if (ipgpc_fid_list[anode->id].info > 0) {
1589 1589 anode = anode->next;
1590 1590 (void) ipgpc_removefilter(fid->filter.filter_name,
1591 1591 fid->filter.filter_instance, flags);
1592 1592 } else {
1593 1593 tnode = anode;
1594 1594 anode = anode->next;
1595 1595 /* free this node */
1596 1596 kmem_cache_free(element_node_cache, tnode);
1597 1597 }
1598 1598 }
1599 1599 /* remove cid from ipgpc_cid_list and decrement ipgpc_num_cls */
1600 1600 ipgpc3dbg(("ipgpc_removeclass: class %s has been removed",
1601 1601 class_name));
1602 1602 removecid(class_id);
1603 1603 mutex_exit(&ipgpc_cid_list_lock); /* release lock */
1604 1604 rc = ipp_action_unref(ipgpc_aid, old_next_action, flags);
1605 1605 ASSERT(rc == 0);
1606 1606 return (0);
1607 1607 }
1608 1608
1609 1609 /*
1610 1610 * ipgpc_modifyfilter(nvlist, flags)
1611 1611 *
1612 1612 * modifies the input filter
1613 1613 * - if in_class != NULL, filter is associated with that class
1614 1614 * - EINVAL is returned if filter name does not exist in nvlist
1615 1615 * - if filter->filter_name does not exist ENOENT is returned
1616 1616 * - if a class name to associate with is not present in nvlist, then the
1617 1617 * previous class association is used
1618 1618 */
1619 1619 int
1620 1620 ipgpc_modifyfilter(nvlist_t **nvlpp, ipp_flags_t flags)
1621 1621 {
1622 1622 unsigned filter_id;
1623 1623 int ret = 0;
1624 1624 int rc;
1625 1625 ipgpc_filter_t *filter;
1626 1626 ipgpc_filter_t old_filter;
1627 1627 char *name;
1628 1628 char *s;
1629 1629 uint_t class_id;
1630 1630
1631 1631 filter = kmem_zalloc(sizeof (ipgpc_filter_t), KM_SLEEP);
1632 1632 if ((ret = ipgpc_parse_filter(filter, *nvlpp)) != 0) {
1633 1633 ipgpc0dbg(("ipgpc_modifyfilter: error %d parsing filter",
1634 1634 ret));
1635 1635 ipgpc_filter_destructor(filter);
1636 1636 kmem_free(filter, sizeof (ipgpc_filter_t));
1637 1637 return (ret);
1638 1638 }
1639 1639
1640 1640 /* parse class name */
1641 1641 if (nvlist_lookup_string(*nvlpp, CLASSIFIER_CLASS_NAME, &name)
1642 1642 != 0) {
1643 1643 name = NULL; /* no class specified */
1644 1644 }
1645 1645
1646 1646 /* modify filter entry */
1647 1647 if ((rc = filter_name2id(&filter_id, filter->filter_name,
1648 1648 filter->filter_instance, ipgpc_num_fltrs)) == EEXIST) {
1649 1649 if (name == NULL) {
1650 1650 /* set class_name to previous class_name association */
1651 1651 class_id = ipgpc_fid_list[filter_id].class_id;
1652 1652 name = ipgpc_cid_list[class_id].aclass.class_name;
1653 1653 } else {
1654 1654 if ((ret = class_name2id(&class_id, name,
1655 1655 ipgpc_num_cls)) != EEXIST) {
1656 1656 ipgpc0dbg(("ipgpc_modifyfilter: class does " \
1657 1657 "not exist"));
1658 1658 ipgpc_filter_destructor(filter);
1659 1659 kmem_free(filter, sizeof (ipgpc_filter_t));
1660 1660 return (ret);
1661 1661 }
1662 1662 }
1663 1663 /* copy out old filter just in case we need to revert */
1664 1664 old_filter = ipgpc_fid_list[filter_id].filter;
1665 1665
1666 1666 /* make copy of filter_comment */
1667 1667 if (ipgpc_fid_list[filter_id].filter.filter_comment != NULL) {
1668 1668 s = ipgpc_fid_list[filter_id].filter.filter_comment;
1669 1669 old_filter.filter_comment =
1670 1670 kmem_alloc((strlen(s) + 1), KM_SLEEP);
1671 1671 (void) strcpy(old_filter.filter_comment, s);
1672 1672 } else {
1673 1673 old_filter.filter_comment = NULL;
1674 1674 }
1675 1675
1676 1676 /* make copy of saddr_hostname */
1677 1677 if (ipgpc_fid_list[filter_id].filter.saddr_hostname != NULL) {
1678 1678 s = ipgpc_fid_list[filter_id].filter.saddr_hostname;
1679 1679 old_filter.saddr_hostname =
1680 1680 kmem_alloc((strlen(s) + 1), KM_SLEEP);
1681 1681 (void) strcpy(old_filter.saddr_hostname, s);
1682 1682 } else {
1683 1683 old_filter.saddr_hostname = NULL;
1684 1684 }
1685 1685
1686 1686 /* make copy of daddr_hostname */
1687 1687 if (ipgpc_fid_list[filter_id].filter.daddr_hostname != NULL) {
1688 1688 s = ipgpc_fid_list[filter_id].filter.daddr_hostname;
1689 1689 old_filter.daddr_hostname =
1690 1690 kmem_alloc((strlen(s) + 1), KM_SLEEP);
1691 1691 (void) strcpy(old_filter.daddr_hostname, s);
1692 1692 } else {
1693 1693 old_filter.daddr_hostname = NULL;
1694 1694 }
1695 1695
1696 1696 /* remove old filter entry */
1697 1697 ret = ipgpc_removefilter(filter->filter_name,
1698 1698 filter->filter_instance, flags);
1699 1699 if (ret == 0) { /* no error, add filter */
1700 1700 ret = ipgpc_addfilter(filter, name, flags);
1701 1701 if (ret != 0) {
1702 1702 /* error occurred, free filter fields */
1703 1703 ipgpc0dbg(("ipgpc_modifyfilter: invalid " \
1704 1704 "filter given, unable to modify " \
1705 1705 "existing filter %s",
1706 1706 filter->filter_name));
1707 1707 ipgpc_filter_destructor(filter);
1708 1708 kmem_free(filter, sizeof (ipgpc_filter_t));
1709 1709 /* revert back to old filter */
1710 1710 (void) ipgpc_addfilter(&old_filter, name,
1711 1711 flags);
1712 1712 return (ret);
1713 1713 }
1714 1714 ipgpc_filter_destructor(&old_filter);
1715 1715 } else {
1716 1716 ipgpc0dbg(("ipgpc_modifyfilter: error %d occurred " \
1717 1717 "when modifying filter", ret));
1718 1718 ipgpc_filter_destructor(&old_filter);
1719 1719 ipgpc_filter_destructor(filter);
1720 1720 kmem_free(filter, sizeof (ipgpc_filter_t));
1721 1721 return (ret);
1722 1722 }
1723 1723 } else {
1724 1724 ipgpc0dbg(("ipgpc_modifyfilter: filter lookup error %d", rc));
1725 1725 return (rc); /* filter name does not exist */
1726 1726 }
1727 1727 kmem_free(filter, sizeof (ipgpc_filter_t));
1728 1728 return (0);
1729 1729 }
1730 1730
1731 1731 /*
1732 1732 * ipgpc_modifyclass(in_class)
1733 1733 *
1734 1734 * if the input class exists, then the action list is modified
1735 1735 * if the input class does not exist, ENOENT is returned
1736 1736 */
1737 1737 /* ARGSUSED */
1738 1738 int
1739 1739 ipgpc_modifyclass(nvlist_t **nvlpp, ipp_flags_t flags)
1740 1740 {
1741 1741 unsigned class_id;
1742 1742 ipgpc_class_t in_class;
1743 1743 char *name;
1744 1744 int rc;
1745 1745 uint32_t gather_stats;
1746 1746 boolean_t ref_action = B_FALSE;
1747 1747 ipp_action_id_t old_next_action;
1748 1748 size_t name_len;
1749 1749
1750 1750 /* parse class name */
1751 1751 if (nvlist_lookup_string(*nvlpp, CLASSIFIER_CLASS_NAME, &name) != 0) {
1752 1752 return (EINVAL); /* class name missing, error */
1753 1753 }
1754 1754 name_len = strlen(name);
1755 1755 /* check for max name length */
1756 1756 if ((name_len + 1) > MAXNAMELEN) {
1757 1757 ipgpc0dbg(("ipgpc_modifyclass: class name length > " \
1758 1758 "MAXNAMELEN"));
1759 1759 return (EINVAL);
1760 1760 }
1761 1761 bcopy(name, in_class.class_name, (name_len + 1));
1762 1762
1763 1763 mutex_enter(&ipgpc_cid_list_lock);
1764 1764 /* look up class name, only existing classes can be modified */
1765 1765 if ((rc = class_name2id(&class_id, in_class.class_name,
1766 1766 ipgpc_num_cls)) == EEXIST) {
1767 1767 /* preserve previous config if values are absent */
1768 1768 /* parse action name */
1769 1769 old_next_action = ipgpc_cid_list[class_id].aclass.next_action;
1770 1770 if (nvlist_lookup_string(*nvlpp, CLASSIFIER_NEXT_ACTION, &name)
1771 1771 != 0) {
1772 1772 /* use previous config */
1773 1773 in_class.next_action = old_next_action;
1774 1774 } else { /* next action name present */
1775 1775 if ((in_class.next_action = ipp_action_lookup(name))
1776 1776 == IPP_ACTION_INVAL) {
1777 1777 ipgpc0dbg(("ipgpc_modifyclass: invalid " \
1778 1778 "action name %s", name));
1779 1779 mutex_exit(&ipgpc_cid_list_lock);
1780 1780 return (EINVAL); /* this is an error */
1781 1781 }
1782 1782 ref_action = B_TRUE;
1783 1783 }
1784 1784 /* parse gather stats byte */
1785 1785 if (nvlist_lookup_uint32(*nvlpp, CLASSIFIER_CLASS_STATS_ENABLE,
1786 1786 &gather_stats) != 0) {
1787 1787 /* use previous config */
1788 1788 in_class.gather_stats =
1789 1789 ipgpc_cid_list[class_id].aclass.gather_stats;
1790 1790 } else {
1791 1791 in_class.gather_stats = (boolean_t)gather_stats;
1792 1792 }
1793 1793 /* check to see if gather_stats booleans differ */
1794 1794 if ((ipgpc_cid_list[class_id].aclass.gather_stats !=
1795 1795 in_class.gather_stats)) {
1796 1796 if (ipgpc_cid_list[class_id].aclass.gather_stats) {
1797 1797 /* delete kstat entry */
1798 1798 if (ipgpc_cid_list[class_id].cl_stats != NULL) {
1799 1799 ipp_stat_destroy(
1800 1800 ipgpc_cid_list[class_id].cl_stats);
1801 1801 ipgpc_cid_list[class_id].cl_stats =
1802 1802 NULL;
1803 1803 }
1804 1804 } else { /* gather_stats == B_FALSE */
1805 1805 if ((rc = class_statinit(&in_class, class_id))
1806 1806 != 0) {
1807 1807 ipgpc0dbg(("ipgpc_modifyclass: " \
1808 1808 "class_statinit failed with " \
1809 1809 "error %d", rc));
1810 1810 mutex_exit(&ipgpc_cid_list_lock);
1811 1811 return (rc);
1812 1812 }
1813 1813 }
1814 1814 }
1815 1815 mutex_exit(&ipgpc_cid_list_lock);
1816 1816 /* check if next_action was modified */
1817 1817 if (ref_action == B_TRUE) {
1818 1818 if ((rc = ipp_action_ref(ipgpc_aid,
1819 1819 in_class.next_action, 0)) != 0) {
1820 1820 ipgpc0dbg(("ipgpc_modifyclass: error " \
1821 1821 "occurred while adding a reference to " \
1822 1822 "the new next_action %d",
1823 1823 in_class.next_action));
1824 1824 mutex_exit(&ipgpc_cid_list_lock);
1825 1825 return (rc);
1826 1826 }
1827 1827 /* fix up references */
1828 1828 rc = ipp_action_unref(ipgpc_aid, old_next_action,
1829 1829 flags);
1830 1830 ASSERT(rc == 0);
1831 1831 }
1832 1832 /* preserve originator id */
1833 1833 in_class.originator =
1834 1834 ipgpc_cid_list[class_id].aclass.originator;
1835 1835 ipgpc_cid_list[class_id].aclass = in_class;
1836 1836 ipgpc_cid_list[class_id].stats.next_action =
1837 1837 in_class.next_action;
1838 1838 } else {
1839 1839 ipgpc0dbg(("ipgpc_modifyclass: class name lookup error %d",
1840 1840 rc));
1841 1841 mutex_exit(&ipgpc_cid_list_lock);
1842 1842 return (rc);
1843 1843 }
1844 1844 return (0);
1845 1845 }
1846 1846
1847 1847
1848 1848 /*
1849 1849 * ipgpc_list_insert(listpp, id)
1850 1850 *
1851 1851 * inserts an item, id, into the list, if item exists EEXIST is returned
1852 1852 */
1853 1853 int
1854 1854 ipgpc_list_insert(linked_list *listpp, key_t id)
1855 1855 {
1856 1856 element_node_t *p;
1857 1857
1858 1858 if (*listpp == NULL) {
1859 1859 *listpp = kmem_cache_alloc(element_node_cache, KM_SLEEP);
1860 1860 (*listpp)->element_refcnt = 1;
1861 1861 (*listpp)->next = NULL;
1862 1862 (*listpp)->id = id;
1863 1863 } else {
1864 1864 for (p = *listpp; p->next != NULL; p = p->next) {
1865 1865 if (p->id == id) {
1866 1866 (*p->element_ref)(p);
1867 1867 return (EEXIST);
1868 1868 }
1869 1869 }
1870 1870 if (p->id == id) {
1871 1871 (*p->element_ref)(p);
1872 1872 return (EEXIST);
1873 1873 } else {
1874 1874 p->next =
1875 1875 kmem_cache_alloc(element_node_cache, KM_SLEEP);
1876 1876 p->next->element_refcnt = 1;
1877 1877 p->next->next = NULL;
1878 1878 p = p->next;
1879 1879 p->id = id;
1880 1880 }
1881 1881 }
1882 1882 return (0);
1883 1883 }
1884 1884
1885 1885 /*
1886 1886 * ipgpc_list_remove(listpp, id)
1887 1887 *
1888 1888 * removes an item, id, from the list if it exists and returns TRUE or FALSE
1889 1889 * if not removed
1890 1890 */
1891 1891 boolean_t
1892 1892 ipgpc_list_remove(element_node_t **listpp, key_t id)
1893 1893 {
1894 1894 element_node_t *p = NULL;
1895 1895 element_node_t *t = NULL;
1896 1896
1897 1897 if (*listpp == NULL) {
1898 1898 return (B_FALSE);
1899 1899 }
1900 1900 if ((*listpp)->id == id) {
1901 1901 p = *listpp;
1902 1902 if ((*listpp)->element_refcnt == 1) {
1903 1903 *listpp = (*listpp)->next;
1904 1904 }
1905 1905 (*p->element_unref)(p);
1906 1906 return (B_TRUE);
1907 1907 } else if ((*listpp)->next != NULL) {
1908 1908 /* linear search for matching id */
1909 1909 for (p = *listpp; p->next != NULL; p = p->next) {
1910 1910 if (p->next->id == id) {
1911 1911 t = p->next;
1912 1912 if (p->next->element_refcnt == 1) {
1913 1913 p->next = p->next->next;
1914 1914 }
1915 1915 (*t->element_unref)(t);
1916 1916 return (B_TRUE);
1917 1917 }
1918 1918 }
1919 1919 }
1920 1920 return (B_FALSE);
1921 1921 }
1922 1922
1923 1923 /*
1924 1924 * Module destroy code
1925 1925 */
1926 1926
1927 1927 static void
1928 1928 removeclasses(ipp_flags_t flags)
1929 1929 {
1930 1930 int i;
1931 1931
1932 1932 for (i = 0; i < ipgpc_max_num_classes; ++i) {
1933 1933 if (ipgpc_cid_list[i].info > 0) {
1934 1934 (void) ipgpc_removeclass(
1935 1935 ipgpc_cid_list[i].aclass.class_name, flags);
1936 1936 }
1937 1937 }
1938 1938 }
1939 1939
1940 1940 static void
1941 1941 freetriev6nodes(node_t **inNode)
1942 1942 {
1943 1943 node_t *anode = *inNode;
1944 1944 node_t *tnode;
1945 1945 node_t *s[130]; /* stack of previous nodes */
1946 1946 int prev_link[130]; /* stack of what the previous link was */
1947 1947 int sp = 0;
1948 1948 node_t *root = *inNode; /* pointer to root node */
1949 1949
1950 1950 s[sp] = NULL;
1951 1951 prev_link[sp] = -1;
1952 1952 /* loop until only the root node remains */
1953 1953 while (!((root->zero == NULL) && (root->one == NULL))) {
1954 1954 if (anode->zero != NULL) { /* check zero node */
1955 1955 tnode = anode;
1956 1956 anode = anode->zero;
1957 1957 s[++sp] = tnode; /* put node on stack */
1958 1958 prev_link[sp] = 0;
1959 1959 } else if (anode->one != NULL) { /* check one node */
1960 1960 tnode = anode;
1961 1961 anode = anode->one;
1962 1962 s[++sp] = tnode; /* put node on stack */
1963 1963 prev_link[sp] = 1;
1964 1964 } else { /* leaf node reached */
1965 1965 /* free leaf node and pop the stack */
1966 1966 kmem_cache_free(trie_node_cache, anode);
1967 1967 anode = s[sp];
1968 1968 if (prev_link[sp--] == 0) {
1969 1969 anode->zero = NULL;
1970 1970 } else {
1971 1971 anode->one = NULL;
1972 1972 }
1973 1973 if (anode == NULL) {
1974 1974 return;
1975 1975 }
1976 1976 }
1977 1977 }
1978 1978 }
1979 1979
1980 1980
1981 1981 void
1982 1982 ipgpc_destroy(ipp_flags_t flags)
1983 1983 {
1984 1984 int i;
1985 1985 int rc;
1986 1986 element_node_t *anode = NULL;
1987 1987 element_node_t *tnode = NULL;
1988 1988 fid_t *fid = NULL;
1989 1989
1990 1990 /* check to see if default class id was set */
1991 1991 if (ipgpc_def_class_id != -1) {
1992 1992 ipp_action_id_t next_action =
1993 1993 ipgpc_cid_list[ipgpc_def_class_id].aclass.next_action;
1994 1994
1995 1995 /* unreference default_class->next_action */
1996 1996 rc = ipp_action_unref(ipgpc_aid, next_action, flags);
1997 1997 ASSERT(rc == 0);
1998 1998 /* removing filter associated with the default class */
1999 1999 anode = ipgpc_cid_list[ipgpc_def_class_id].filter_list;
2000 2000 while (anode != NULL) {
2001 2001 fid = &ipgpc_fid_list[anode->id];
2002 2002 if (ipgpc_fid_list[anode->id].info > 0) {
2003 2003 anode = anode->next;
2004 2004 (void) ipgpc_removefilter(
2005 2005 fid->filter.filter_name,
2006 2006 fid->filter.filter_instance, flags);
2007 2007 } else {
2008 2008 tnode = anode;
2009 2009 anode = anode->next;
2010 2010 /* free this node */
2011 2011 kmem_cache_free(element_node_cache, tnode);
2012 2012 }
2013 2013 }
2014 2014 ASSERT(ipgpc_cid_list[ipgpc_def_class_id].filter_list == NULL);
2015 2015 removecid(ipgpc_def_class_id);
2016 2016 ASSERT(ipgpc_cid_list[ipgpc_def_class_id].info == -1);
2017 2017 ipgpc_def_class_id = -1;
2018 2018 }
2019 2019 /* remove stats entries */
2020 2020 if (ipgpc_global_stats != NULL) {
2021 2021 /* destroy global stats */
2022 2022 ipp_stat_destroy(ipgpc_global_stats);
2023 2023 ipgpc_global_stats = NULL;
2024 2024 }
2025 2025
2026 2026 /*
2027 2027 * remove all classes, which will remove all filters, stats and
2028 2028 * selectors
2029 2029 */
2030 2030 if (ipgpc_cid_list != NULL) {
2031 2031 removeclasses(flags);
2032 2032 kmem_free(ipgpc_cid_list,
2033 2033 sizeof (cid_t) * ipgpc_max_num_classes);
2034 2034 ipgpc_cid_list = NULL;
2035 2035 }
2036 2036 /* all filters and classes should have been removed at this point */
2037 2037 ASSERT((ipgpc_num_cls == 0) && (ipgpc_num_fltrs == 0));
2038 2038
2039 2039 /* free filter id list structure */
2040 2040 if (ipgpc_fid_list != NULL) {
2041 2041 kmem_free(ipgpc_fid_list,
2042 2042 sizeof (fid_t) * ipgpc_max_num_filters);
2043 2043 ipgpc_fid_list = NULL;
2044 2044 }
2045 2045
2046 2046 /*
2047 2047 * IPv6 address tries don't implement path compression or node
2048 2048 * deletions, like v4/port tries. All allocated nodes must be freed
2049 2049 * before trie root node is destroyed
2050 2050 */
2051 2051 if (ipgpc_trie_list[IPGPC_TRIE_SADDRID6].trie != NULL) {
2052 2052 freetriev6nodes(&ipgpc_trie_list[IPGPC_TRIE_SADDRID6].trie);
2053 2053 /* free trie root */
2054 2054 kmem_cache_free(trie_node_cache,
2055 2055 ipgpc_trie_list[IPGPC_TRIE_SADDRID6].trie);
2056 2056 /* destroy lock */
2057 2057 rw_destroy(&ipgpc_trie_list[IPGPC_TRIE_SADDRID6].rw_lock);
2058 2058 ipgpc_trie_list[IPGPC_TRIE_SADDRID6].trie = NULL;
2059 2059 }
2060 2060 if (ipgpc_trie_list[IPGPC_TRIE_DADDRID6].trie != NULL) {
2061 2061 freetriev6nodes(&ipgpc_trie_list[IPGPC_TRIE_DADDRID6].trie);
2062 2062 /* free trie root */
2063 2063 kmem_cache_free(trie_node_cache,
2064 2064 ipgpc_trie_list[IPGPC_TRIE_DADDRID6].trie);
2065 2065 /* destroy lock */
2066 2066 rw_destroy(&ipgpc_trie_list[IPGPC_TRIE_DADDRID6].rw_lock);
2067 2067 ipgpc_trie_list[IPGPC_TRIE_DADDRID6].trie = NULL;
2068 2068 }
2069 2069
2070 2070 /* free remaining tries structures */
2071 2071 for (i = 0; i < (NUM_TRIES - 2); ++i) {
2072 2072 if (ipgpc_trie_list[i].trie != NULL) {
2073 2073 /* free trie root */
2074 2074 kmem_cache_free(trie_node_cache,
2075 2075 ipgpc_trie_list[i].trie);
2076 2076 /* destroy lock */
2077 2077 rw_destroy(&ipgpc_trie_list[i].rw_lock);
2078 2078 ipgpc_trie_list[i].trie = NULL;
2079 2079 }
2080 2080 }
2081 2081
2082 2082 /* destroy caches */
2083 2083 if (ht_node_cache != NULL) {
2084 2084 kmem_cache_destroy(ht_node_cache);
2085 2085 ht_node_cache = NULL;
2086 2086 }
2087 2087 if (trie_node_cache != NULL) {
2088 2088 kmem_cache_destroy(trie_node_cache);
2089 2089 trie_node_cache = NULL;
2090 2090 }
2091 2091 if (element_node_cache != NULL) {
2092 2092 kmem_cache_destroy(element_node_cache);
2093 2093 element_node_cache = NULL;
2094 2094 }
2095 2095 if (ht_match_cache != NULL) {
2096 2096 kmem_cache_destroy(ht_match_cache);
2097 2097 ht_match_cache = NULL;
2098 2098 }
2099 2099 }
2100 2100
2101 2101 /*
2102 2102 * Module info code
2103 2103 */
2104 2104
2105 2105 /*
2106 2106 * ipgpc_params_info(fn, arg)
2107 2107 *
2108 2108 * allocates, builds and passes an nvlist to fn with arg
2109 2109 */
2110 2110 int
2111 2111 ipgpc_params_info(int (*fn)(nvlist_t *, void *), void *arg)
2112 2112 {
2113 2113 nvlist_t *nvlp;
2114 2114 int rc;
2115 2115
2116 2116 /* allocate nvlist to be passed back */
2117 2117 if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, KM_NOSLEEP)) != 0) {
2118 2118 return (rc);
2119 2119 }
2120 2120
2121 2121 /* add config type */
2122 2122 if ((rc = nvlist_add_byte(nvlp, IPP_CONFIG_TYPE, IPP_SET)) != 0) {
2123 2123 nvlist_free(nvlp);
2124 2124 return (rc);
2125 2125 }
2126 2126
2127 2127 /* add gather stats boolean */
2128 2128 if ((rc = nvlist_add_uint32(nvlp, IPP_ACTION_STATS_ENABLE,
2129 2129 (uint32_t)ipgpc_gather_stats)) != 0) {
2130 2130 nvlist_free(nvlp);
2131 2131 return (rc);
2132 2132 }
2133 2133
2134 2134 /* call back with nvlist */
2135 2135 rc = fn(nvlp, arg);
2136 2136
2137 2137 nvlist_free(nvlp);
2138 2138
2139 2139 return (rc);
2140 2140 }
2141 2141
2142 2142 /*
2143 2143 * build_class_nvlist(nvlpp, in_class)
2144 2144 *
2145 2145 * build an nvlist based on in_class
2146 2146 * if isdefault, add apporiate configuration type to nvlpp
2147 2147 */
2148 2148 static int
2149 2149 build_class_nvlist(nvlist_t **nvlpp, ipgpc_class_t *in_class,
2150 2150 boolean_t isdefault)
2151 2151 {
2152 2152 nvlist_t *nvlp = *nvlpp;
2153 2153 char *next_action;
2154 2154 int rc;
2155 2155
2156 2156 /*
2157 2157 * add configuration type
2158 2158 * if class is the default class, config type should be
2159 2159 * CLASSIFIER_MODIFY_CLASS
2160 2160 * otherwise it should be CLASSIFIER_ADD_CLASS
2161 2161 */
2162 2162 /* add config type */
2163 2163 if ((rc = nvlist_add_byte(nvlp, IPP_CONFIG_TYPE,
2164 2164 ((isdefault) ? CLASSIFIER_MODIFY_CLASS : CLASSIFIER_ADD_CLASS)))
2165 2165 != 0) {
2166 2166 return (rc);
2167 2167 }
2168 2168
2169 2169 /* add class name */
2170 2170 if ((rc = nvlist_add_string(nvlp, CLASSIFIER_CLASS_NAME,
2171 2171 in_class->class_name)) != 0) {
2172 2172 return (rc);
2173 2173 }
2174 2174
2175 2175 /* add originator */
2176 2176 if ((rc = nvlist_add_uint32(nvlp, IPP_CONFIG_ORIGINATOR,
2177 2177 in_class->originator)) != 0) {
2178 2178 return (rc);
2179 2179 }
2180 2180
2181 2181 /* look up next action name with next action id */
2182 2182 if ((rc = ipp_action_name(in_class->next_action, &next_action)) != 0) {
2183 2183 return (rc);
2184 2184 }
2185 2185
2186 2186 /* add next action name */
2187 2187 if ((rc = nvlist_add_string(nvlp, CLASSIFIER_NEXT_ACTION,
2188 2188 next_action)) != 0) {
2189 2189 kmem_free(next_action, (strlen(next_action) + 1));
2190 2190 return (rc);
2191 2191 }
2192 2192
2193 2193 kmem_free(next_action, (strlen(next_action) + 1));
2194 2194
2195 2195 /* add gather stats boolean */
2196 2196 if ((rc = nvlist_add_uint32(nvlp, CLASSIFIER_CLASS_STATS_ENABLE,
2197 2197 (uint32_t)in_class->gather_stats)) != 0) {
2198 2198 return (rc);
2199 2199 }
2200 2200
2201 2201 return (0);
2202 2202 }
2203 2203
2204 2204
2205 2205 /*
2206 2206 * ipgpc_classes_info(fn, arg)
2207 2207 *
2208 2208 * foreach class, allocate, build and pass an nvlist to fn with arg
2209 2209 */
2210 2210 int
2211 2211 ipgpc_classes_info(int (*fn)(nvlist_t *, void *), void *arg)
2212 2212 {
2213 2213 int i;
2214 2214 int rc;
2215 2215 nvlist_t *nvlp;
2216 2216
2217 2217 for (i = 0; i < ipgpc_max_num_classes; ++i) {
2218 2218 if (ipgpc_cid_list[i].info <= 0) {
2219 2219 /* cid not allocated for this entry */
2220 2220 continue;
2221 2221 }
2222 2222 /* allocate an nvlist */
2223 2223 if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, KM_NOSLEEP))
2224 2224 != 0) {
2225 2225 return (rc);
2226 2226 }
2227 2227 /* build an nvlist for this particular class */
2228 2228 if ((rc = (build_class_nvlist(&nvlp,
2229 2229 &ipgpc_cid_list[i].aclass,
2230 2230 ((i == ipgpc_def_class_id) ? B_TRUE : B_FALSE)))) != 0) {
2231 2231 nvlist_free(nvlp);
2232 2232 return (rc);
2233 2233 }
2234 2234 /* call back with nvlist */
2235 2235 if ((rc = fn(nvlp, arg)) != 0) {
2236 2236 nvlist_free(nvlp);
2237 2237 return (rc);
2238 2238 }
2239 2239
2240 2240 nvlist_free(nvlp); /* free nvlist and continue */
2241 2241 }
2242 2242
2243 2243 return (0);
2244 2244 }
2245 2245
2246 2246 /*
2247 2247 * build_filter_nvlist(nvlpp, in_filter, class_name)
2248 2248 *
2249 2249 * build an nvlist based on in_filter and class_name.
2250 2250 * Only non-wildcard/dontcare selectors are added to the nvlist.
2251 2251 */
2252 2252 static int
2253 2253 build_filter_nvlist(nvlist_t **nvlpp, ipgpc_filter_t *in_filter,
2254 2254 char *class_name)
2255 2255 {
2256 2256 nvlist_t *nvlp = *nvlpp;
2257 2257 int rc;
2258 2258 in6_addr_t zero_addr = IN6ADDR_ANY_INIT;
2259 2259
2260 2260 /* add filter name */
2261 2261 if ((rc = nvlist_add_string(nvlp, CLASSIFIER_FILTER_NAME,
2262 2262 in_filter->filter_name)) != 0) {
2263 2263 return (rc);
2264 2264 }
2265 2265
2266 2266 /* add class name */
2267 2267 if ((rc = nvlist_add_string(nvlp, CLASSIFIER_CLASS_NAME, class_name))
2268 2268 != 0) {
2269 2269 return (rc);
2270 2270 }
2271 2271
2272 2272 /* add originator */
2273 2273 if ((rc = nvlist_add_uint32(nvlp, IPP_CONFIG_ORIGINATOR,
2274 2274 in_filter->originator)) != 0) {
2275 2275 return (rc);
2276 2276 }
2277 2277
2278 2278 /* add configuration type of CLASSIFIER_ADD_FILTER */
2279 2279 if ((rc = nvlist_add_byte(nvlp, IPP_CONFIG_TYPE,
2280 2280 CLASSIFIER_ADD_FILTER)) != 0) {
2281 2281 return (rc);
2282 2282 }
2283 2283
2284 2284 /* add uid */
2285 2285 if (in_filter->uid != IPGPC_WILDCARD) {
2286 2286 if ((rc = nvlist_add_uint32(nvlp, IPGPC_UID, in_filter->uid))
2287 2287 != 0) {
2288 2288 return (rc);
2289 2289 }
2290 2290 }
2291 2291
2292 2292 /* add projid */
2293 2293 if (in_filter->projid != IPGPC_WILDCARD) {
2294 2294 if ((rc = nvlist_add_int32(nvlp, IPGPC_PROJID,
2295 2295 in_filter->projid)) != 0) {
2296 2296 return (rc);
2297 2297 }
2298 2298 }
2299 2299
2300 2300 /* add interface index */
2301 2301 if (in_filter->if_index != IPGPC_UNSPECIFIED) {
2302 2302 if ((rc = nvlist_add_uint32(nvlp, IPGPC_IF_INDEX,
2303 2303 in_filter->if_index)) != 0) {
2304 2304 return (rc);
2305 2305 }
2306 2306 }
2307 2307
2308 2308 /* add direction */
2309 2309 if (in_filter->direction != IPGPC_UNSPECIFIED) {
2310 2310 if ((rc = nvlist_add_uint32(nvlp, IPGPC_DIR,
2311 2311 in_filter->direction)) != 0) {
2312 2312 return (rc);
2313 2313 }
2314 2314 }
2315 2315
2316 2316 /* add protocol */
2317 2317 if (in_filter->proto != IPGPC_UNSPECIFIED) {
2318 2318 if ((rc = nvlist_add_byte(nvlp, IPGPC_PROTO, in_filter->proto))
2319 2319 != 0) {
2320 2320 return (rc);
2321 2321 }
2322 2322 }
2323 2323
2324 2324 /* add dsfield and mask */
2325 2325 if (in_filter->dsfield_mask != 0) {
2326 2326 if ((rc = nvlist_add_byte(nvlp, IPGPC_DSFIELD,
2327 2327 in_filter->dsfield)) != 0) {
2328 2328 return (rc);
2329 2329 }
2330 2330 if ((rc = nvlist_add_byte(nvlp, IPGPC_DSFIELD_MASK,
2331 2331 in_filter->dsfield_mask)) != 0) {
2332 2332 return (rc);
2333 2333 }
2334 2334 }
2335 2335
2336 2336 /* add source address, mask and hostname */
2337 2337 if (!(IN6_ARE_ADDR_EQUAL(&in_filter->saddr_mask, &zero_addr))) {
2338 2338 if ((rc = nvlist_add_uint32_array(nvlp, IPGPC_SADDR,
2339 2339 in_filter->saddr.s6_addr32, 4)) != 0) {
2340 2340 return (rc);
2341 2341 }
2342 2342
2343 2343 if ((rc = nvlist_add_uint32_array(nvlp, IPGPC_SADDR_MASK,
2344 2344 in_filter->saddr_mask.s6_addr32, 4)) != 0) {
2345 2345 return (rc);
2346 2346 }
2347 2347
2348 2348 if (in_filter->saddr_hostname != NULL) {
2349 2349 if ((rc = nvlist_add_string(nvlp, IPGPC_SADDR_HOSTNAME,
2350 2350 in_filter->saddr_hostname)) != 0) {
2351 2351 return (rc);
2352 2352 }
2353 2353 }
2354 2354 }
2355 2355
2356 2356 /* add destination address, mask and hostname */
2357 2357 if (!(IN6_ARE_ADDR_EQUAL(&in_filter->daddr_mask, &zero_addr))) {
2358 2358 if ((rc = nvlist_add_uint32_array(nvlp, IPGPC_DADDR,
2359 2359 in_filter->daddr.s6_addr32, 4)) != 0) {
2360 2360 return (rc);
2361 2361 }
2362 2362 if ((rc = nvlist_add_uint32_array(nvlp, IPGPC_DADDR_MASK,
2363 2363 in_filter->daddr_mask.s6_addr32, 4)) != 0) {
2364 2364 return (rc);
2365 2365 }
2366 2366 if (in_filter->daddr_hostname != NULL) {
2367 2367 if ((rc = nvlist_add_string(nvlp, IPGPC_DADDR_HOSTNAME,
2368 2368 in_filter->daddr_hostname)) != 0) {
2369 2369 return (rc);
2370 2370 }
2371 2371 }
2372 2372 }
2373 2373
2374 2374 /* add source port and mask */
2375 2375 if (in_filter->sport_mask != 0) {
2376 2376 if ((rc = nvlist_add_uint16(nvlp, IPGPC_SPORT,
2377 2377 in_filter->sport)) != 0) {
2378 2378 return (rc);
2379 2379 }
2380 2380 if ((rc = nvlist_add_uint16(nvlp, IPGPC_SPORT_MASK,
2381 2381 in_filter->sport_mask)) != 0) {
2382 2382 return (rc);
2383 2383 }
2384 2384 }
2385 2385
2386 2386 /* add destination port and mask */
2387 2387 if (in_filter->dport_mask != 0) {
2388 2388 if ((rc = nvlist_add_uint16(nvlp, IPGPC_DPORT,
2389 2389 in_filter->dport)) != 0) {
2390 2390 return (rc);
2391 2391 }
2392 2392 if ((rc = nvlist_add_uint16(nvlp, IPGPC_DPORT_MASK,
2393 2393 in_filter->dport_mask)) != 0) {
2394 2394 return (rc);
2395 2395 }
2396 2396 }
2397 2397
2398 2398 /* add precedence */
2399 2399 if (in_filter->precedence != UINT_MAX) {
2400 2400 if ((rc = nvlist_add_uint32(nvlp, IPGPC_PRECEDENCE,
2401 2401 in_filter->precedence)) != 0) {
2402 2402 return (rc);
2403 2403 }
2404 2404 }
2405 2405
2406 2406 /* add priority */
2407 2407 if (in_filter->priority != 0) {
2408 2408 if ((rc = nvlist_add_uint32(nvlp, IPGPC_PRIORITY,
2409 2409 in_filter->priority)) != 0) {
2410 2410 return (rc);
2411 2411 }
2412 2412 }
2413 2413
2414 2414 /* add filter type */
2415 2415 if (in_filter->filter_type != IPGPC_GENERIC_FLTR) {
2416 2416 if ((rc = nvlist_add_byte(nvlp, IPGPC_FILTER_TYPE,
2417 2417 in_filter->filter_type)) != 0) {
2418 2418 return (rc);
2419 2419 }
2420 2420 }
2421 2421
2422 2422 /* add filter instance */
2423 2423 if (in_filter->filter_instance != -1) {
2424 2424 if ((rc = nvlist_add_int32(nvlp, IPGPC_FILTER_INSTANCE,
2425 2425 in_filter->filter_instance)) != 0) {
2426 2426 return (rc);
2427 2427 }
2428 2428 }
2429 2429
2430 2430 /* add filter private field */
2431 2431 if (in_filter->filter_comment != NULL) {
2432 2432 if ((rc = nvlist_add_string(nvlp, IPGPC_FILTER_PRIVATE,
2433 2433 in_filter->filter_comment)) != 0) {
2434 2434 return (rc);
2435 2435 }
2436 2436 }
2437 2437
2438 2438 return (0);
2439 2439 }
2440 2440
2441 2441 /*
2442 2442 * ipgpc_filters_info(fn, arg)
2443 2443 *
2444 2444 * for each filter, allocate, build and pass an nvlist to fn with arg
2445 2445 */
2446 2446 int
2447 2447 ipgpc_filters_info(int (*fn)(nvlist_t *, void *), void *arg)
2448 2448 {
2449 2449 int i;
2450 2450 int rc;
2451 2451 nvlist_t *nvlp;
2452 2452 int class_id;
2453 2453
2454 2454 for (i = 0; i < ipgpc_max_num_filters; ++i) {
2455 2455 if (ipgpc_fid_list[i].info <= 0) {
2456 2456 /* fid not allocated for this entry */
2457 2457 continue;
2458 2458 }
2459 2459 /* allocate an nvlist */
2460 2460 if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, KM_NOSLEEP))
2461 2461 != 0) {
2462 2462 return (rc);
2463 2463 }
2464 2464 class_id = ipgpc_fid_list[i].class_id;
2465 2465 /* build an nvlist for this particular filter */
2466 2466 if ((rc = (build_filter_nvlist(&nvlp,
2467 2467 &ipgpc_fid_list[i].filter,
2468 2468 ipgpc_cid_list[class_id].aclass.class_name))) != 0) {
2469 2469 nvlist_free(nvlp);
2470 2470 return (rc);
2471 2471 }
2472 2472 /* call back with nvlist */
2473 2473 if ((rc = fn(nvlp, arg)) != 0) {
2474 2474 nvlist_free(nvlp);
2475 2475 return (rc);
2476 2476 }
2477 2477
2478 2478 nvlist_free(nvlp); /* free nvlist and continue */
2479 2479 }
2480 2480 return (0);
2481 2481 }
2482 2482
2483 2483 /*
2484 2484 * Module invoke code
2485 2485 */
2486 2486
2487 2487 /*
2488 2488 * ipgpc_findfilters(in_id, key, fid_table)
2489 2489 *
2490 2490 * returns a list of matching filters for searching the given structure
2491 2491 * associated with the input id with the input key
2492 2492 * - returns DONTCARE_ONLY_MATCH if the selector structure described by
2493 2493 * in_id contains only dontcares
2494 2494 * - returns NO_MATCHES if no filters were found and no dontcares exist
2495 2495 * for a given selector
2496 2496 * - ENOMEM is returned if memory error occurs
2497 2497 * - NORMAL_MATCH on success
2498 2498 */
2499 2499 int
2500 2500 ipgpc_findfilters(int in_id, int key, ht_match_t *fid_table)
2501 2501 {
2502 2502 int num_found = 0;
2503 2503
2504 2504 if (in_id == IPGPC_BA_DSID) { /* special search for DSFIELD */
2505 2505 if (ipgpc_ds_table_id.info.dontcareonly == B_TRUE) {
2506 2506 /* trie is loaded with only DONTCARE(*) keys */
2507 2507 return (DONTCARE_ONLY_MATCH);
2508 2508 }
2509 2509 num_found = ba_retrieve(&ipgpc_ds_table_id, (uint8_t)key,
2510 2510 fid_table);
2511 2511 /* check to see if no matches were made */
2512 2512 if ((num_found == 0) &&
2513 2513 (ipgpc_ds_table_id.stats.num_dontcare == 0)) {
2514 2514 return (NO_MATCHES);
2515 2515 }
2516 2516 } else if (in_id >= TABLE_ID_OFFSET) { /* table to search */
2517 2517 table_id_t *taid = &ipgpc_table_list[in_id - TABLE_ID_OFFSET];
2518 2518
2519 2519 if (taid->info.dontcareonly == B_TRUE) {
2520 2520 /* trie is loaded with only DONTCARE(*) keys */
2521 2521 return (DONTCARE_ONLY_MATCH);
2522 2522 }
2523 2523 num_found = ht_retrieve(taid, key, fid_table);
2524 2524 /* check to see if no matches were made */
2525 2525 if ((num_found == 0) && (taid->stats.num_dontcare == 0)) {
2526 2526 return (NO_MATCHES);
2527 2527 }
2528 2528 } else { /* trie to search */
2529 2529 trie_id_t *tid = &ipgpc_trie_list[in_id];
2530 2530
2531 2531 if (tid->info.dontcareonly == B_TRUE) {
2532 2532 /* trie is loaded with only DONTCARE(*) keys */
2533 2533 return (DONTCARE_ONLY_MATCH);
2534 2534 }
2535 2535 /* search the trie for matches */
2536 2536 num_found = t_retrieve(tid, key, fid_table);
2537 2537 /* check to see if no matches were made */
2538 2538 if ((num_found == 0) && (tid->stats.num_dontcare == 0)) {
2539 2539 return (NO_MATCHES);
2540 2540 }
2541 2541 }
2542 2542 if (num_found == -1) { /* num_found == -1 if memory error */
2543 2543 return (ENOMEM);
2544 2544 } else {
2545 2545 return (NORMAL_MATCH);
2546 2546 }
2547 2547 }
2548 2548
2549 2549 /*
2550 2550 * ipgpc_findfilters6(in_id, key, fid_table)
2551 2551 *
2552 2552 * findfilters specific to IPv6 traffic
2553 2553 */
2554 2554 int
2555 2555 ipgpc_findfilters6(int in_id, in6_addr_t key, ht_match_t *fid_table)
2556 2556 {
2557 2557 trie_id_t *tid = &ipgpc_trie_list[in_id];
2558 2558 int num_found = 0;
2559 2559
2560 2560 if (tid->info.dontcareonly == B_TRUE) {
2561 2561 /* trie is loaded with only DONTCARE(*) keys */
2562 2562 return (DONTCARE_ONLY_MATCH);
2563 2563 }
2564 2564 /* search the trie for matches */
2565 2565 num_found = t_retrieve6(tid, key, fid_table);
2566 2566 /* check to see if no matches were made */
2567 2567 if ((num_found == 0) && (tid->stats.num_dontcare == 0)) {
2568 2568 return (NO_MATCHES);
2569 2569 } else if (num_found == -1) { /* num_found == -1 if memory error */
2570 2570 return (ENOMEM);
2571 2571 } else {
2572 2572 return (NORMAL_MATCH);
2573 2573 }
2574 2574 }
2575 2575
2576 2576 /*
2577 2577 * ht_match_insert(a, id, mask)
2578 2578 *
2579 2579 * inserts id into table and applies mask to match_map
2580 2580 * returns ENOMEM if can't allocate ht_match_t node, 0 otherwise
2581 2581 */
2582 2582 static int
2583 2583 ht_match_insert(ht_match_t *a, int id, uint16_t mask)
2584 2584 {
2585 2585 int x = (id % HASH_SIZE); /* has for index */
2586 2586 ht_match_t *p = NULL;
2587 2587
2588 2588 if ((a[x].key == id) || (a[x].key == 0)) {
2589 2589 a[x].key = id;
2590 2590 a[x].match_map |= mask;
2591 2591 } else if (a[x].next == NULL) {
2592 2592 a[x].next = kmem_cache_alloc(ht_match_cache, KM_NOSLEEP);
2593 2593 if (a[x].next == NULL) {
2594 2594 ipgpc0dbg(("ht_match_insert(): kmem_cache_alloc " \
2595 2595 "error"));
2596 2596 return (ENOMEM);
2597 2597 }
2598 2598 a[x].next->next = NULL;
2599 2599 a[x].next->key = id;
2600 2600 a[x].next->match_map = mask;
2601 2601 } else {
2602 2602
2603 2603 p = a[x].next;
2604 2604 while (p != NULL) {
2605 2605 if (p->key == id) {
2606 2606 p->match_map |= mask;
2607 2607 return (0);
2608 2608 }
2609 2609 p = p->next;
2610 2610 }
2611 2611 p = kmem_cache_alloc(ht_match_cache, KM_NOSLEEP);
2612 2612 if (p == NULL) {
2613 2613 ipgpc0dbg(("ht_match_insert(): kmem_cache_alloc " \
2614 2614 "error"));
2615 2615 return (ENOMEM);
2616 2616 }
2617 2617 p->key = id;
2618 2618 p->match_map = mask;
2619 2619 p->next = a[x].next;
2620 2620 a[x].next = p;
2621 2621 }
2622 2622 return (0);
2623 2623 }
2624 2624
2625 2625 /*
2626 2626 * ipgpc_mark_found(mask, list, fid_table)
2627 2627 *
2628 2628 * given a list of filter ids and a mask for the selector that is being marked,
2629 2629 * the ids are inserted (or updated) in the fid_table to being marked as
2630 2630 * matched for the given selector
2631 2631 * return -1 if memory error
2632 2632 */
2633 2633 int
2634 2634 ipgpc_mark_found(uint16_t mask, linked_list list, ht_match_t *fid_table)
2635 2635 {
2636 2636 linked_list tnode = NULL;
2637 2637 int num_found = 0;
2638 2638
2639 2639 for (tnode = list; tnode != NULL; tnode = tnode->next) {
2640 2640 /* apply the trie mask to the match map for this element */
2641 2641 if (ipgpc_fid_list[tnode->id].info > 0) {
2642 2642 if (ht_match_insert(fid_table, tnode->id, mask)
2643 2643 == ENOMEM) {
2644 2644 return (-1);
2645 2645 }
2646 2646 ++num_found;
2647 2647 }
2648 2648 }
2649 2649 return (num_found);
2650 2650 }
2651 2651
2652 2652 /* updates global stats for ipgpc */
2653 2653 /* ARGSUSED */
2654 2654 static int
2655 2655 update_global_stats(ipp_stat_t *sp, void *arg, int rw)
2656 2656 {
2657 2657 globalstats_t *gbl_stats = (globalstats_t *)sp->ipps_data;
2658 2658 uint32_t num_filters = (uint32_t)ipgpc_num_fltrs;
2659 2659 uint32_t num_classes = (uint32_t)ipgpc_num_cls;
2660 2660
2661 2661 ASSERT(gbl_stats != NULL);
2662 2662 (void) ipp_stat_named_op(&gbl_stats->nfilters, &num_filters, rw);
2663 2663 (void) ipp_stat_named_op(&gbl_stats->nclasses, &num_classes, rw);
2664 2664 (void) ipp_stat_named_op(&gbl_stats->nbytes, &ipgpc_nbytes, rw);
2665 2665 (void) ipp_stat_named_op(&gbl_stats->npackets, &ipgpc_npackets, rw);
2666 2666 (void) ipp_stat_named_op(&gbl_stats->epackets, &ipgpc_epackets, rw);
2667 2667 return (0);
2668 2668 }
2669 2669
2670 2670
2671 2671 /* updates class stats for a specific class */
2672 2672 static int
2673 2673 update_class_stats(ipp_stat_t *sp, void *arg, int rw)
2674 2674 {
2675 2675 ipgpc_class_stats_t *stats = (ipgpc_class_stats_t *)arg;
2676 2676 classstats_t *cl_stats = (classstats_t *)sp->ipps_data;
2677 2677
2678 2678 ASSERT(stats != NULL);
2679 2679 ASSERT(cl_stats != NULL);
2680 2680 (void) ipp_stat_named_op(&cl_stats->nbytes, &stats->nbytes, rw);
2681 2681 (void) ipp_stat_named_op(&cl_stats->npackets, &stats->npackets, rw);
2682 2682 (void) ipp_stat_named_op(&cl_stats->last_match, &stats->last_match, rw);
2683 2683 return (0);
2684 2684 }
↓ open down ↓ |
1146 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX