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/classifierddi.c
+++ new/usr/src/uts/common/ipp/ipgpc/classifierddi.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/systm.h>
27 27 #include <sys/socket.h>
28 28 #include <netinet/in.h>
29 29 #include <sys/modctl.h>
30 30 #include <sys/sunddi.h>
31 31 #include <ipp/ipp.h>
32 32 #include <ipp/ipp_config.h>
33 33 #include <ipp/ipgpc/classifier.h>
34 34 #include <inet/ip.h>
35 35 #include <net/if.h>
36 36 #include <inet/ip_if.h>
37 37 #include <inet/ipp_common.h>
38 38
39 39 /* DDI file for ipgpc ipp module */
40 40
41 41 /* protects against multiple configs */
42 42 static kmutex_t ipgpc_config_lock;
43 43
44 44 static int ipgpc_create_action(ipp_action_id_t, nvlist_t **, ipp_flags_t);
45 45 static int ipgpc_modify_action(ipp_action_id_t, nvlist_t **, ipp_flags_t);
46 46 static int ipgpc_destroy_action(ipp_action_id_t, ipp_flags_t);
47 47 static int ipgpc_info(ipp_action_id_t aid, int (*)(nvlist_t *, void *), void *,
48 48 ipp_flags_t);
49 49 static int ipgpc_invoke_action(ipp_action_id_t, ipp_packet_t *);
50 50
51 51 ipp_ops_t ipgpc_ops = {
52 52 IPPO_REV,
53 53 ipgpc_create_action, /* ippo_action_create */
54 54 ipgpc_modify_action, /* ippo_action_modify */
55 55 ipgpc_destroy_action, /* ippo_action_destroy */
56 56 ipgpc_info, /* ippo_action_info */
57 57 ipgpc_invoke_action /* ippo_action_invoke */
58 58 };
59 59
60 60 extern struct mod_ops mod_ippops;
61 61
62 62 /*
63 63 * Module linkage information for the kernel.
64 64 */
65 65 static struct modlipp modlipp = {
66 66 &mod_ippops,
67 67 "IP Generic Packet Classifier (ipgpc) module 1.0",
68 68 &ipgpc_ops
69 69 };
70 70
71 71 static struct modlinkage modlinkage = {
72 72 MODREV_1,
73 73 (void *)&modlipp,
74 74 NULL
75 75 };
76 76
77 77 #define __FN__ "_init"
78 78 int
79 79 _init(
80 80 void)
81 81 {
82 82 int rc;
83 83
84 84 if (ipgpc_action_exist) {
85 85 return (EBUSY);
86 86 }
87 87 /* init mutexes */
88 88 mutex_init(&ipgpc_config_lock, NULL, MUTEX_DRIVER, NULL);
89 89 mutex_init(&ipgpc_fid_list_lock, NULL, MUTEX_DRIVER, NULL);
90 90 mutex_init(&ipgpc_cid_list_lock, NULL, MUTEX_DRIVER, NULL);
91 91 mutex_init(&ipgpc_table_list_lock, NULL, MUTEX_DRIVER, NULL);
92 92 mutex_init(&ipgpc_ds_table_id.lock, NULL, MUTEX_DRIVER, NULL);
93 93
94 94 if ((rc = mod_install(&modlinkage)) != 0) {
95 95 /* clean up after fail */
96 96 mutex_destroy(&ipgpc_config_lock);
97 97 mutex_destroy(&ipgpc_fid_list_lock);
98 98 mutex_destroy(&ipgpc_cid_list_lock);
99 99 mutex_destroy(&ipgpc_table_list_lock);
100 100 mutex_destroy(&ipgpc_ds_table_id.lock);
101 101 }
102 102
103 103 return (rc);
104 104 }
105 105 #undef __FN__
106 106
107 107 #define __FN__ "_fini"
108 108 int
109 109 _fini(
110 110 void)
111 111 {
112 112 int rc;
113 113
114 114 if (ipgpc_action_exist) {
115 115 return (EBUSY);
116 116 }
117 117
118 118 if ((rc = mod_remove(&modlinkage)) != 0) {
119 119 return (rc);
120 120 }
121 121 /* destroy mutexes */
122 122 mutex_destroy(&ipgpc_config_lock);
123 123 mutex_destroy(&ipgpc_fid_list_lock);
124 124 mutex_destroy(&ipgpc_cid_list_lock);
125 125 mutex_destroy(&ipgpc_table_list_lock);
126 126 mutex_destroy(&ipgpc_ds_table_id.lock);
127 127 return (rc);
128 128 }
129 129 #undef __FN__
130 130
131 131 #define __FN__ "_info"
132 132 int
133 133 _info(
134 134 struct modinfo *modinfop)
135 135 {
136 136 return (mod_info(&modlinkage, modinfop));
137 137 }
138 138 #undef __FN__
139 139
140 140 /*
141 141 * ipgpc_create_action(aid, nvlpp, flags)
142 142 *
143 143 * creates a single instance of ipgpc, if one does not exist. If an action
144 144 * instance already exists, fail with EBUSY
145 145 *
146 146 * if nvlpp contains the name IPP_ACTION_STATS_ENABLE, then process it and
147 147 * determine if global stats should be collected
148 148 *
149 149 * the ipgpc_config_lock is taken to block out any other creates or destroys
150 150 * the are issued while the create is taking place
151 151 */
152 152 /* ARGSUSED */
153 153 static int
154 154 ipgpc_create_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags)
155 155 {
156 156 int rc;
157 157 uint32_t stat;
158 158 nvlist_t *nvlp;
159 159
160 160 nvlp = *nvlpp;
161 161 *nvlpp = NULL; /* nvlist should be NULL when this returns */
162 162
163 163 /* only one ipgpc action instance can be loaded at once */
164 164 if (ipgpc_action_exist) {
165 165 nvlist_free(nvlp);
166 166 return (EBUSY);
167 167 } else {
168 168 mutex_enter(&ipgpc_config_lock);
169 169 if (ipgpc_action_exist) {
170 170 nvlist_free(nvlp);
171 171 mutex_exit(&ipgpc_config_lock);
172 172 return (EBUSY);
173 173 }
174 174 /* check for action param IPP_ACTION_STATS_ENABLE */
175 175 if ((rc = nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE,
176 176 &stat)) != 0) {
177 177 ipgpc_gather_stats = B_FALSE; /* disabled by default */
178 178 } else {
179 179 ipgpc_gather_stats = (boolean_t)stat;
180 180 }
181 181 if ((rc = ipgpc_initialize(aid)) != 0) {
182 182 ipgpc0dbg(("ipgpc_create_action: ipgpc_intialize " \
183 183 "error %d", rc));
184 184 ipgpc_destroy(IPP_DESTROY_REF);
185 185 ipgpc_action_exist = B_FALSE;
186 186 nvlist_free(nvlp);
187 187 mutex_exit(&ipgpc_config_lock);
188 188 return (rc);
189 189 }
190 190 ipgpc_action_exist = B_TRUE;
191 191 nvlist_free(nvlp);
192 192 mutex_exit(&ipgpc_config_lock);
193 193 return (0);
194 194 }
195 195 }
196 196
197 197 /*
198 198 * ipgpc_modify_action
199 199 *
200 200 * modify an instance of ipgpc
201 201 *
202 202 * nvlpp will contain the configuration type to switch off of. Use this
203 203 * to determine what modification should be made. If the modification fails,
204 204 * return the appropriate error.
205 205 */
206 206 /* ARGSUSED */
207 207 static int
208 208 ipgpc_modify_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags)
209 209 {
210 210 nvlist_t *nvlp;
211 211 int rc = 0;
212 212 uint8_t config_type;
213 213 uint32_t stat;
214 214 char *name;
215 215 int32_t filter_instance;
216 216 ipgpc_filter_t *filter;
217 217 ipgpc_class_t *aclass;
218 218
219 219 nvlp = *nvlpp;
220 220 *nvlpp = NULL; /* nvlist should be NULL when this returns */
221 221
222 222 if ((rc = nvlist_lookup_byte(nvlp, IPP_CONFIG_TYPE, &config_type))
223 223 != 0) {
224 224 nvlist_free(nvlp);
225 225 ipgpc0dbg(("ipgpc_modify_action: invalid configuration type"));
226 226 return (EINVAL);
227 227 }
228 228
229 229 switch (config_type) {
230 230 case IPP_SET: /* set an action parameter */
231 231 if ((rc = nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE,
232 232 &stat)) != 0) {
233 233 nvlist_free(nvlp);
234 234 ipgpc0dbg(("ipgpc_modify_action: invalid IPP_SET " \
235 235 "parameter"));
236 236 return (EINVAL);
237 237 } else {
238 238 ipgpc_gather_stats = (boolean_t)stat;
239 239 }
240 240 break;
241 241 case CLASSIFIER_ADD_FILTER: /* add a filter */
242 242 filter = kmem_zalloc(sizeof (ipgpc_filter_t), KM_SLEEP);
243 243 if ((rc = ipgpc_parse_filter(filter, nvlp)) != 0) {
244 244 ipgpc0dbg(("ipgpc_modify_action: invalid filter"));
245 245 ipgpc_filter_destructor(filter);
246 246 kmem_free(filter, sizeof (ipgpc_filter_t));
247 247 break;
248 248 }
249 249 /* parse class name */
250 250 if ((rc = nvlist_lookup_string(nvlp, CLASSIFIER_CLASS_NAME,
251 251 &name)) != 0) {
252 252 ipgpc0dbg(("ipgpc_modify_action: class name missing"));
253 253 ipgpc_filter_destructor(filter);
254 254 kmem_free(filter, sizeof (ipgpc_filter_t));
255 255 break;
256 256 }
257 257 rc = ipgpc_addfilter(filter, name, flags);
258 258 if (rc != 0) {
259 259 ipgpc_filter_destructor(filter);
260 260 }
261 261 kmem_free(filter, sizeof (ipgpc_filter_t));
262 262 break;
263 263 case CLASSIFIER_ADD_CLASS: /* add a class */
264 264 aclass = kmem_zalloc(sizeof (ipgpc_class_t), KM_SLEEP);
265 265 if ((rc = ipgpc_parse_class(aclass, nvlp)) != 0) {
266 266 ipgpc0dbg(("ipgpc_modify_action: invalid class"));
267 267 kmem_free(aclass, sizeof (ipgpc_class_t));
268 268 break;
269 269 }
270 270 rc = ipgpc_addclass(aclass, flags);
271 271 kmem_free(aclass, sizeof (ipgpc_class_t));
272 272 break;
273 273 case CLASSIFIER_REMOVE_FILTER: /* remove a filter */
274 274 /* parse filter name */
275 275 if ((rc = nvlist_lookup_string(nvlp, CLASSIFIER_FILTER_NAME,
276 276 &name)) != 0) {
277 277 ipgpc0dbg(("ipgpc_modify_action: filtername missing"));
278 278 break;
279 279 }
280 280 /* parse optional filter_instance */
281 281 if (nvlist_lookup_int32(nvlp, IPGPC_FILTER_INSTANCE,
282 282 &filter_instance) != 0) {
283 283 filter_instance = -1;
284 284 }
285 285 rc = ipgpc_removefilter(name, filter_instance, flags);
286 286 break;
287 287 case CLASSIFIER_REMOVE_CLASS: /* remove a class */
288 288 /* parse class name */
289 289 if ((rc = nvlist_lookup_string(nvlp, CLASSIFIER_CLASS_NAME,
290 290 &name)) != 0) {
291 291 ipgpc0dbg(("ipgpc_modify_action: class name missing"));
292 292 break;
293 293 }
294 294 rc = ipgpc_removeclass(name, flags);
295 295 break;
296 296 case CLASSIFIER_MODIFY_FILTER: /* modify a filter */
297 297 rc = ipgpc_modifyfilter(&nvlp, flags);
298 298 break;
299 299 case CLASSIFIER_MODIFY_CLASS: /* modify a class */
300 300 rc = ipgpc_modifyclass(&nvlp, flags);
301 301 break;
302 302 default: /* invalid config type */
303 303 nvlist_free(nvlp);
304 304 ipgpc0dbg(("ipgpc_modify_action:invalid configuration type %u",
305 305 config_type));
306 306 return (EINVAL);
307 307 }
308 308 nvlist_free(nvlp); /* free the list */
309 309 return (rc); /* nvlist is passed back NULL */
310 310 }
311 311
312 312 /*
313 313 * ipgpc_destroy_action(aid, flags)
314 314 *
315 315 * action destructor for ipgpc
316 316 *
317 317 * Destroys an instance of the ipgpc action, if one exists. The
318 318 * ipgpc_action_lock is taken to block out any other destroys or creates
319 319 * that might be issued while the action is being destroyed
320 320 */
321 321 /* ARGSUSED */
322 322 static int
323 323 ipgpc_destroy_action(ipp_action_id_t aid, ipp_flags_t flags)
324 324 {
325 325 /* only destroy action if it exists */
326 326 if (ipgpc_action_exist == B_TRUE) {
327 327 mutex_enter(&ipgpc_config_lock);
328 328 if (ipgpc_action_exist == B_FALSE) {
329 329 mutex_exit(&ipgpc_config_lock);
330 330 return (EBUSY);
331 331 }
332 332 ipgpc_action_exist = B_FALSE;
333 333 ipgpc_destroy(flags);
334 334 mutex_exit(&ipgpc_config_lock);
335 335 }
336 336 return (0);
337 337 }
338 338
339 339 /*
340 340 * ipgpc_info(aid, fn, arg)
341 341 *
342 342 * configuration quering function for ipgpc
343 343 *
344 344 * passes back the configuration of ipgpc through allocated nvlists
345 345 * all action paramaters, classes and filters are built into nvlists
346 346 * and passed to the function pointer fn with arg
347 347 */
348 348 /* ARGSUSED */
349 349 static int
350 350 ipgpc_info(ipp_action_id_t aid, int (*fn)(nvlist_t *, void *), void *arg,
351 351 ipp_flags_t flags)
352 352 {
353 353 int rc;
354 354
355 355 /* set parameters */
356 356 if ((rc = ipgpc_params_info(fn, arg)) != 0) {
357 357 return (rc);
358 358 }
359 359
360 360 /* set all classes */
361 361 if ((rc = ipgpc_classes_info(fn, arg)) != 0) {
362 362 return (rc);
363 363 }
364 364
365 365 /* set all filters */
366 366 if ((rc = ipgpc_filters_info(fn, arg)) != 0) {
367 367 return (rc);
368 368 }
369 369 return (0);
370 370 }
371 371
372 372 /*
373 373 * ipgpc_invoke_action(aid, packet)
374 374 *
375 375 * packet processing function for ipgpc
376 376 *
377 377 * given packet the selector information is parsed and the classify
378 378 * function is called with those selectors. The classify function will
379 379 * return either a class or NULL, which represents a memory error and
380 380 * ENOMEM is returned. If the class returned is not NULL, the class and next
381 381 * action, associated with that class, are added to packet
382 382 */
383 383 /* ARGSUSED */
384 384 static int
385 385 ipgpc_invoke_action(ipp_action_id_t aid, ipp_packet_t *packet)
386 386 {
387 387 ipgpc_class_t *out_class;
388 388 hrtime_t start, end;
389 389 mblk_t *mp = NULL;
390 390 ip_priv_t *priv = NULL;
391 391 ill_t *ill = NULL;
392 392 ipha_t *ipha;
393 393 ip_proc_t callout_pos;
394 394 int af;
395 395 int rc;
396 396 ipgpc_packet_t pkt;
397 397 uint_t ill_idx;
398 398
399 399 /* extract packet data */
400 400 mp = ipp_packet_get_data(packet);
401 401 ASSERT(mp != NULL);
402 402
403 403 priv = (ip_priv_t *)ipp_packet_get_private(packet);
404 404 ASSERT(priv != NULL);
405 405
↓ open down ↓ |
405 lines elided |
↑ open up ↑ |
406 406 callout_pos = priv->proc;
407 407 ill_idx = priv->ill_index;
408 408
409 409 /* If we don't get an M_DATA, then return an error */
410 410 if (mp->b_datap->db_type != M_DATA) {
411 411 if ((mp->b_cont != NULL) &&
412 412 (mp->b_cont->b_datap->db_type == M_DATA)) {
413 413 mp = mp->b_cont; /* jump over the M_CTL into M_DATA */
414 414 } else {
415 415 ipgpc0dbg(("ipgpc_invoke_action: no data\n"));
416 - atomic_add_64(&ipgpc_epackets, 1);
416 + atomic_inc_64(&ipgpc_epackets);
417 417 return (EINVAL);
418 418 }
419 419 }
420 420
421 421 /*
422 422 * Translate the callout_pos into the direction the packet is traveling
423 423 */
424 424 if (callout_pos != IPP_LOCAL_IN) {
425 425 if (callout_pos & IPP_LOCAL_OUT) {
426 426 callout_pos = IPP_LOCAL_OUT;
427 427 } else if (callout_pos & IPP_FWD_IN) {
428 428 callout_pos = IPP_FWD_IN;
429 429 } else { /* IPP_FWD_OUT */
430 430 callout_pos = IPP_FWD_OUT;
431 431 }
432 432 }
433 433
434 434 /* parse the packet from the message block */
435 435 ipha = (ipha_t *)mp->b_rptr;
436 436 /* Determine IP Header Version */
437 437 if (IPH_HDR_VERSION(ipha) == IPV4_VERSION) {
438 438 parse_packet(&pkt, mp);
439 439 af = AF_INET;
440 440 } else {
441 441 parse_packet6(&pkt, mp);
442 442 af = AF_INET6;
443 443 }
444 444
445 445 pkt.direction = callout_pos; /* set packet direction */
446 446
447 447 /* The ill_index could be 0 when called from forwarding (read) path */
448 448 if (ill_idx > 0)
449 449 ill = ill_lookup_on_ifindex_global_instance(ill_idx, B_FALSE);
450 450
451 451 if (ill != NULL) {
452 452 /*
453 453 * Since all IPP actions in an IPMP group are performed
454 454 * relative to the IPMP group interface, if this is an
455 455 * underlying interface in an IPMP group, use the IPMP
456 456 * group interface's index.
457 457 */
458 458 if (IS_UNDER_IPMP(ill))
459 459 pkt.if_index = ipmp_ill_get_ipmp_ifindex(ill);
460 460 else
461 461 pkt.if_index = ill->ill_phyint->phyint_ifindex;
462 462 /* Got the field from the ILL, go ahead and refrele */
463 463 ill_refrele(ill);
464 464 } else {
465 465 /* unknown if_index */
466 466 pkt.if_index = IPGPC_UNSPECIFIED;
467 467 }
468 468
469 469 if (ipgpc_debug > 5) {
470 470 /* print pkt under high debug level */
471 471 #ifdef IPGPC_DEBUG
472 472 print_packet(af, &pkt);
473 473 #endif
474 474 }
475 475 if (ipgpc_debug > 3) {
476 476 start = gethrtime(); /* start timer */
477 477 }
↓ open down ↓ |
51 lines elided |
↑ open up ↑ |
478 478
479 479 /* classify this packet */
480 480 out_class = ipgpc_classify(af, &pkt);
481 481
482 482 if (ipgpc_debug > 3) {
483 483 end = gethrtime(); /* stop timer */
484 484 }
485 485
486 486 /* ipgpc_classify will only return NULL if a memory error occured */
487 487 if (out_class == NULL) {
488 - atomic_add_64(&ipgpc_epackets, 1);
488 + atomic_inc_64(&ipgpc_epackets);
489 489 return (ENOMEM);
490 490 }
491 491
492 492 ipgpc1dbg(("ipgpc_invoke_action: class = %s", out_class->class_name));
493 493 /* print time to classify(..) */
494 494 ipgpc2dbg(("ipgpc_invoke_action: time = %lld nsec\n", (end - start)));
495 495
496 496 if ((rc = ipp_packet_add_class(packet, out_class->class_name,
497 497 out_class->next_action)) != 0) {
498 - atomic_add_64(&ipgpc_epackets, 1);
498 + atomic_inc_64(&ipgpc_epackets);
499 499 ipgpc0dbg(("ipgpc_invoke_action: ipp_packet_add_class " \
500 500 "failed with error %d", rc));
501 501 return (rc);
502 502 }
503 503 return (ipp_packet_next(packet, IPP_ACTION_CONT));
504 504 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX