10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 53448Sdh155122 * Common Development and Distribution License (the "License"). 63448Sdh155122 * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*8485SPeter.Memishian@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #include <sys/systm.h> 270Sstevel@tonic-gate #include <sys/socket.h> 280Sstevel@tonic-gate #include <netinet/in.h> 290Sstevel@tonic-gate #include <sys/modctl.h> 300Sstevel@tonic-gate #include <sys/sunddi.h> 310Sstevel@tonic-gate #include <ipp/ipp.h> 320Sstevel@tonic-gate #include <ipp/ipp_config.h> 330Sstevel@tonic-gate #include <ipp/ipgpc/classifier.h> 340Sstevel@tonic-gate #include <inet/ip.h> 350Sstevel@tonic-gate #include <net/if.h> 360Sstevel@tonic-gate #include <inet/ip_if.h> 370Sstevel@tonic-gate #include <inet/ipp_common.h> 380Sstevel@tonic-gate 390Sstevel@tonic-gate /* DDI file for ipgpc ipp module */ 400Sstevel@tonic-gate 410Sstevel@tonic-gate /* protects against multiple configs */ 420Sstevel@tonic-gate static kmutex_t ipgpc_config_lock; 430Sstevel@tonic-gate 440Sstevel@tonic-gate static int ipgpc_create_action(ipp_action_id_t, nvlist_t **, ipp_flags_t); 450Sstevel@tonic-gate static int ipgpc_modify_action(ipp_action_id_t, nvlist_t **, ipp_flags_t); 460Sstevel@tonic-gate static int ipgpc_destroy_action(ipp_action_id_t, ipp_flags_t); 470Sstevel@tonic-gate static int ipgpc_info(ipp_action_id_t aid, int (*)(nvlist_t *, void *), void *, 480Sstevel@tonic-gate ipp_flags_t); 490Sstevel@tonic-gate static int ipgpc_invoke_action(ipp_action_id_t, ipp_packet_t *); 500Sstevel@tonic-gate 510Sstevel@tonic-gate ipp_ops_t ipgpc_ops = { 520Sstevel@tonic-gate IPPO_REV, 530Sstevel@tonic-gate ipgpc_create_action, /* ippo_action_create */ 540Sstevel@tonic-gate ipgpc_modify_action, /* ippo_action_modify */ 550Sstevel@tonic-gate ipgpc_destroy_action, /* ippo_action_destroy */ 560Sstevel@tonic-gate ipgpc_info, /* ippo_action_info */ 570Sstevel@tonic-gate ipgpc_invoke_action /* ippo_action_invoke */ 580Sstevel@tonic-gate }; 590Sstevel@tonic-gate 600Sstevel@tonic-gate extern struct mod_ops mod_ippops; 610Sstevel@tonic-gate 620Sstevel@tonic-gate /* 630Sstevel@tonic-gate * Module linkage information for the kernel. 640Sstevel@tonic-gate */ 650Sstevel@tonic-gate static struct modlipp modlipp = { 660Sstevel@tonic-gate &mod_ippops, 670Sstevel@tonic-gate "IP Generic Packet Classifier (ipgpc) module 1.0", 680Sstevel@tonic-gate &ipgpc_ops 690Sstevel@tonic-gate }; 700Sstevel@tonic-gate 710Sstevel@tonic-gate static struct modlinkage modlinkage = { 720Sstevel@tonic-gate MODREV_1, 730Sstevel@tonic-gate (void *)&modlipp, 740Sstevel@tonic-gate NULL 750Sstevel@tonic-gate }; 760Sstevel@tonic-gate 770Sstevel@tonic-gate #define __FN__ "_init" 780Sstevel@tonic-gate int 790Sstevel@tonic-gate _init( 800Sstevel@tonic-gate void) 810Sstevel@tonic-gate { 820Sstevel@tonic-gate int rc; 830Sstevel@tonic-gate 840Sstevel@tonic-gate if (ipgpc_action_exist) { 850Sstevel@tonic-gate return (EBUSY); 860Sstevel@tonic-gate } 870Sstevel@tonic-gate /* init mutexes */ 880Sstevel@tonic-gate mutex_init(&ipgpc_config_lock, NULL, MUTEX_DRIVER, NULL); 890Sstevel@tonic-gate mutex_init(&ipgpc_fid_list_lock, NULL, MUTEX_DRIVER, NULL); 900Sstevel@tonic-gate mutex_init(&ipgpc_cid_list_lock, NULL, MUTEX_DRIVER, NULL); 910Sstevel@tonic-gate mutex_init(&ipgpc_table_list_lock, NULL, MUTEX_DRIVER, NULL); 920Sstevel@tonic-gate mutex_init(&ipgpc_ds_table_id.lock, NULL, MUTEX_DRIVER, NULL); 930Sstevel@tonic-gate 940Sstevel@tonic-gate if ((rc = mod_install(&modlinkage)) != 0) { 950Sstevel@tonic-gate /* clean up after fail */ 960Sstevel@tonic-gate mutex_destroy(&ipgpc_config_lock); 970Sstevel@tonic-gate mutex_destroy(&ipgpc_fid_list_lock); 980Sstevel@tonic-gate mutex_destroy(&ipgpc_cid_list_lock); 990Sstevel@tonic-gate mutex_destroy(&ipgpc_table_list_lock); 1000Sstevel@tonic-gate mutex_destroy(&ipgpc_ds_table_id.lock); 1010Sstevel@tonic-gate } 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate return (rc); 1040Sstevel@tonic-gate } 1050Sstevel@tonic-gate #undef __FN__ 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate #define __FN__ "_fini" 1080Sstevel@tonic-gate int 1090Sstevel@tonic-gate _fini( 1100Sstevel@tonic-gate void) 1110Sstevel@tonic-gate { 1120Sstevel@tonic-gate int rc; 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate if (ipgpc_action_exist) { 1150Sstevel@tonic-gate return (EBUSY); 1160Sstevel@tonic-gate } 1170Sstevel@tonic-gate 1180Sstevel@tonic-gate if ((rc = mod_remove(&modlinkage)) != 0) { 1190Sstevel@tonic-gate return (rc); 1200Sstevel@tonic-gate } 1210Sstevel@tonic-gate /* destroy mutexes */ 1220Sstevel@tonic-gate mutex_destroy(&ipgpc_config_lock); 1230Sstevel@tonic-gate mutex_destroy(&ipgpc_fid_list_lock); 1240Sstevel@tonic-gate mutex_destroy(&ipgpc_cid_list_lock); 1250Sstevel@tonic-gate mutex_destroy(&ipgpc_table_list_lock); 1260Sstevel@tonic-gate mutex_destroy(&ipgpc_ds_table_id.lock); 1270Sstevel@tonic-gate return (rc); 1280Sstevel@tonic-gate } 1290Sstevel@tonic-gate #undef __FN__ 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate #define __FN__ "_info" 1320Sstevel@tonic-gate int 1330Sstevel@tonic-gate _info( 1340Sstevel@tonic-gate struct modinfo *modinfop) 1350Sstevel@tonic-gate { 1360Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1370Sstevel@tonic-gate } 1380Sstevel@tonic-gate #undef __FN__ 1390Sstevel@tonic-gate 1400Sstevel@tonic-gate /* 1410Sstevel@tonic-gate * ipgpc_create_action(aid, nvlpp, flags) 1420Sstevel@tonic-gate * 1430Sstevel@tonic-gate * creates a single instance of ipgpc, if one does not exist. If an action 1440Sstevel@tonic-gate * instance already exists, fail with EBUSY 1450Sstevel@tonic-gate * 1460Sstevel@tonic-gate * if nvlpp contains the name IPP_ACTION_STATS_ENABLE, then process it and 1470Sstevel@tonic-gate * determine if global stats should be collected 1480Sstevel@tonic-gate * 1490Sstevel@tonic-gate * the ipgpc_config_lock is taken to block out any other creates or destroys 1500Sstevel@tonic-gate * the are issued while the create is taking place 1510Sstevel@tonic-gate */ 1520Sstevel@tonic-gate /* ARGSUSED */ 1530Sstevel@tonic-gate static int 1540Sstevel@tonic-gate ipgpc_create_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags) 1550Sstevel@tonic-gate { 1560Sstevel@tonic-gate int rc; 1570Sstevel@tonic-gate uint32_t stat; 1580Sstevel@tonic-gate nvlist_t *nvlp; 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate nvlp = *nvlpp; 1610Sstevel@tonic-gate *nvlpp = NULL; /* nvlist should be NULL when this returns */ 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate /* only one ipgpc action instance can be loaded at once */ 1640Sstevel@tonic-gate if (ipgpc_action_exist) { 1650Sstevel@tonic-gate nvlist_free(nvlp); 1660Sstevel@tonic-gate return (EBUSY); 1670Sstevel@tonic-gate } else { 1680Sstevel@tonic-gate mutex_enter(&ipgpc_config_lock); 1690Sstevel@tonic-gate if (ipgpc_action_exist) { 1700Sstevel@tonic-gate nvlist_free(nvlp); 1710Sstevel@tonic-gate mutex_exit(&ipgpc_config_lock); 1720Sstevel@tonic-gate return (EBUSY); 1730Sstevel@tonic-gate } 1740Sstevel@tonic-gate /* check for action param IPP_ACTION_STATS_ENABLE */ 1750Sstevel@tonic-gate if ((rc = nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE, 1760Sstevel@tonic-gate &stat)) != 0) { 1770Sstevel@tonic-gate ipgpc_gather_stats = B_FALSE; /* disabled by default */ 1780Sstevel@tonic-gate } else { 1790Sstevel@tonic-gate ipgpc_gather_stats = (boolean_t)stat; 1800Sstevel@tonic-gate } 1810Sstevel@tonic-gate if ((rc = ipgpc_initialize(aid)) != 0) { 1820Sstevel@tonic-gate ipgpc0dbg(("ipgpc_create_action: ipgpc_intialize " \ 1830Sstevel@tonic-gate "error %d", rc)); 1840Sstevel@tonic-gate ipgpc_destroy(IPP_DESTROY_REF); 1850Sstevel@tonic-gate ipgpc_action_exist = B_FALSE; 1860Sstevel@tonic-gate nvlist_free(nvlp); 1870Sstevel@tonic-gate mutex_exit(&ipgpc_config_lock); 1880Sstevel@tonic-gate return (rc); 1890Sstevel@tonic-gate } 1900Sstevel@tonic-gate ipgpc_action_exist = B_TRUE; 1910Sstevel@tonic-gate nvlist_free(nvlp); 1920Sstevel@tonic-gate mutex_exit(&ipgpc_config_lock); 1930Sstevel@tonic-gate return (0); 1940Sstevel@tonic-gate } 1950Sstevel@tonic-gate } 1960Sstevel@tonic-gate 1970Sstevel@tonic-gate /* 1980Sstevel@tonic-gate * ipgpc_modify_action 1990Sstevel@tonic-gate * 2000Sstevel@tonic-gate * modify an instance of ipgpc 2010Sstevel@tonic-gate * 2020Sstevel@tonic-gate * nvlpp will contain the configuration type to switch off of. Use this 2030Sstevel@tonic-gate * to determine what modification should be made. If the modification fails, 2040Sstevel@tonic-gate * return the appropriate error. 2050Sstevel@tonic-gate */ 2060Sstevel@tonic-gate /* ARGSUSED */ 2070Sstevel@tonic-gate static int 2080Sstevel@tonic-gate ipgpc_modify_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags) 2090Sstevel@tonic-gate { 2100Sstevel@tonic-gate nvlist_t *nvlp; 2110Sstevel@tonic-gate int rc = 0; 2120Sstevel@tonic-gate uint8_t config_type; 2130Sstevel@tonic-gate uint32_t stat; 2140Sstevel@tonic-gate char *name; 2150Sstevel@tonic-gate int32_t filter_instance; 2160Sstevel@tonic-gate ipgpc_filter_t *filter; 2170Sstevel@tonic-gate ipgpc_class_t *aclass; 2180Sstevel@tonic-gate 2190Sstevel@tonic-gate nvlp = *nvlpp; 2200Sstevel@tonic-gate *nvlpp = NULL; /* nvlist should be NULL when this returns */ 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate if ((rc = nvlist_lookup_byte(nvlp, IPP_CONFIG_TYPE, &config_type)) 2230Sstevel@tonic-gate != 0) { 2240Sstevel@tonic-gate nvlist_free(nvlp); 2250Sstevel@tonic-gate ipgpc0dbg(("ipgpc_modify_action: invalid configuration type")); 2260Sstevel@tonic-gate return (EINVAL); 2270Sstevel@tonic-gate } 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate switch (config_type) { 2300Sstevel@tonic-gate case IPP_SET: /* set an action parameter */ 2310Sstevel@tonic-gate if ((rc = nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE, 2320Sstevel@tonic-gate &stat)) != 0) { 2330Sstevel@tonic-gate nvlist_free(nvlp); 2340Sstevel@tonic-gate ipgpc0dbg(("ipgpc_modify_action: invalid IPP_SET " \ 2350Sstevel@tonic-gate "parameter")); 2360Sstevel@tonic-gate return (EINVAL); 2370Sstevel@tonic-gate } else { 2380Sstevel@tonic-gate ipgpc_gather_stats = (boolean_t)stat; 2390Sstevel@tonic-gate } 2400Sstevel@tonic-gate break; 2410Sstevel@tonic-gate case CLASSIFIER_ADD_FILTER: /* add a filter */ 2420Sstevel@tonic-gate filter = kmem_zalloc(sizeof (ipgpc_filter_t), KM_SLEEP); 2430Sstevel@tonic-gate if ((rc = ipgpc_parse_filter(filter, nvlp)) != 0) { 2440Sstevel@tonic-gate ipgpc0dbg(("ipgpc_modify_action: invalid filter")); 2450Sstevel@tonic-gate ipgpc_filter_destructor(filter); 2460Sstevel@tonic-gate kmem_free(filter, sizeof (ipgpc_filter_t)); 2470Sstevel@tonic-gate break; 2480Sstevel@tonic-gate } 2490Sstevel@tonic-gate /* parse class name */ 2500Sstevel@tonic-gate if ((rc = nvlist_lookup_string(nvlp, CLASSIFIER_CLASS_NAME, 2510Sstevel@tonic-gate &name)) != 0) { 2520Sstevel@tonic-gate ipgpc0dbg(("ipgpc_modify_action: class name missing")); 2530Sstevel@tonic-gate ipgpc_filter_destructor(filter); 2540Sstevel@tonic-gate kmem_free(filter, sizeof (ipgpc_filter_t)); 2550Sstevel@tonic-gate break; 2560Sstevel@tonic-gate } 2570Sstevel@tonic-gate rc = ipgpc_addfilter(filter, name, flags); 2580Sstevel@tonic-gate if (rc != 0) { 2590Sstevel@tonic-gate ipgpc_filter_destructor(filter); 2600Sstevel@tonic-gate } 2610Sstevel@tonic-gate kmem_free(filter, sizeof (ipgpc_filter_t)); 2620Sstevel@tonic-gate break; 2630Sstevel@tonic-gate case CLASSIFIER_ADD_CLASS: /* add a class */ 2640Sstevel@tonic-gate aclass = kmem_zalloc(sizeof (ipgpc_class_t), KM_SLEEP); 2650Sstevel@tonic-gate if ((rc = ipgpc_parse_class(aclass, nvlp)) != 0) { 2660Sstevel@tonic-gate ipgpc0dbg(("ipgpc_modify_action: invalid class")); 2670Sstevel@tonic-gate kmem_free(aclass, sizeof (ipgpc_class_t)); 2680Sstevel@tonic-gate break; 2690Sstevel@tonic-gate } 2700Sstevel@tonic-gate rc = ipgpc_addclass(aclass, flags); 2710Sstevel@tonic-gate kmem_free(aclass, sizeof (ipgpc_class_t)); 2720Sstevel@tonic-gate break; 2730Sstevel@tonic-gate case CLASSIFIER_REMOVE_FILTER: /* remove a filter */ 2740Sstevel@tonic-gate /* parse filter name */ 2750Sstevel@tonic-gate if ((rc = nvlist_lookup_string(nvlp, CLASSIFIER_FILTER_NAME, 2760Sstevel@tonic-gate &name)) != 0) { 2770Sstevel@tonic-gate ipgpc0dbg(("ipgpc_modify_action: filtername missing")); 2780Sstevel@tonic-gate break; 2790Sstevel@tonic-gate } 2800Sstevel@tonic-gate /* parse optional filter_instance */ 2810Sstevel@tonic-gate if (nvlist_lookup_int32(nvlp, IPGPC_FILTER_INSTANCE, 2820Sstevel@tonic-gate &filter_instance) != 0) { 2830Sstevel@tonic-gate filter_instance = -1; 2840Sstevel@tonic-gate } 2850Sstevel@tonic-gate rc = ipgpc_removefilter(name, filter_instance, flags); 2860Sstevel@tonic-gate break; 2870Sstevel@tonic-gate case CLASSIFIER_REMOVE_CLASS: /* remove a class */ 2880Sstevel@tonic-gate /* parse class name */ 2890Sstevel@tonic-gate if ((rc = nvlist_lookup_string(nvlp, CLASSIFIER_CLASS_NAME, 2900Sstevel@tonic-gate &name)) != 0) { 2910Sstevel@tonic-gate ipgpc0dbg(("ipgpc_modify_action: class name missing")); 2920Sstevel@tonic-gate break; 2930Sstevel@tonic-gate } 2940Sstevel@tonic-gate rc = ipgpc_removeclass(name, flags); 2950Sstevel@tonic-gate break; 2960Sstevel@tonic-gate case CLASSIFIER_MODIFY_FILTER: /* modify a filter */ 2970Sstevel@tonic-gate rc = ipgpc_modifyfilter(&nvlp, flags); 2980Sstevel@tonic-gate break; 2990Sstevel@tonic-gate case CLASSIFIER_MODIFY_CLASS: /* modify a class */ 3000Sstevel@tonic-gate rc = ipgpc_modifyclass(&nvlp, flags); 3010Sstevel@tonic-gate break; 3020Sstevel@tonic-gate default: /* invalid config type */ 3030Sstevel@tonic-gate nvlist_free(nvlp); 3040Sstevel@tonic-gate ipgpc0dbg(("ipgpc_modify_action:invalid configuration type %u", 3050Sstevel@tonic-gate config_type)); 3060Sstevel@tonic-gate return (EINVAL); 3070Sstevel@tonic-gate } 3080Sstevel@tonic-gate nvlist_free(nvlp); /* free the list */ 3090Sstevel@tonic-gate return (rc); /* nvlist is passed back NULL */ 3100Sstevel@tonic-gate } 3110Sstevel@tonic-gate 3120Sstevel@tonic-gate /* 3130Sstevel@tonic-gate * ipgpc_destroy_action(aid, flags) 3140Sstevel@tonic-gate * 3150Sstevel@tonic-gate * action destructor for ipgpc 3160Sstevel@tonic-gate * 3170Sstevel@tonic-gate * Destroys an instance of the ipgpc action, if one exists. The 3180Sstevel@tonic-gate * ipgpc_action_lock is taken to block out any other destroys or creates 3190Sstevel@tonic-gate * that might be issued while the action is being destroyed 3200Sstevel@tonic-gate */ 3210Sstevel@tonic-gate /* ARGSUSED */ 3220Sstevel@tonic-gate static int 3230Sstevel@tonic-gate ipgpc_destroy_action(ipp_action_id_t aid, ipp_flags_t flags) 3240Sstevel@tonic-gate { 3250Sstevel@tonic-gate /* only destroy action if it exists */ 3260Sstevel@tonic-gate if (ipgpc_action_exist == B_TRUE) { 3270Sstevel@tonic-gate mutex_enter(&ipgpc_config_lock); 3280Sstevel@tonic-gate if (ipgpc_action_exist == B_FALSE) { 3290Sstevel@tonic-gate mutex_exit(&ipgpc_config_lock); 3300Sstevel@tonic-gate return (EBUSY); 3310Sstevel@tonic-gate } 3320Sstevel@tonic-gate ipgpc_action_exist = B_FALSE; 3330Sstevel@tonic-gate ipgpc_destroy(flags); 3340Sstevel@tonic-gate mutex_exit(&ipgpc_config_lock); 3350Sstevel@tonic-gate } 3360Sstevel@tonic-gate return (0); 3370Sstevel@tonic-gate } 3380Sstevel@tonic-gate 3390Sstevel@tonic-gate /* 3400Sstevel@tonic-gate * ipgpc_info(aid, fn, arg) 3410Sstevel@tonic-gate * 3420Sstevel@tonic-gate * configuration quering function for ipgpc 3430Sstevel@tonic-gate * 3440Sstevel@tonic-gate * passes back the configuration of ipgpc through allocated nvlists 3450Sstevel@tonic-gate * all action paramaters, classes and filters are built into nvlists 3460Sstevel@tonic-gate * and passed to the function pointer fn with arg 3470Sstevel@tonic-gate */ 3480Sstevel@tonic-gate /* ARGSUSED */ 3490Sstevel@tonic-gate static int 3500Sstevel@tonic-gate ipgpc_info(ipp_action_id_t aid, int (*fn)(nvlist_t *, void *), void *arg, 3510Sstevel@tonic-gate ipp_flags_t flags) 3520Sstevel@tonic-gate { 3530Sstevel@tonic-gate int rc; 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate /* set parameters */ 3560Sstevel@tonic-gate if ((rc = ipgpc_params_info(fn, arg)) != 0) { 3570Sstevel@tonic-gate return (rc); 3580Sstevel@tonic-gate } 3590Sstevel@tonic-gate 3600Sstevel@tonic-gate /* set all classes */ 3610Sstevel@tonic-gate if ((rc = ipgpc_classes_info(fn, arg)) != 0) { 3620Sstevel@tonic-gate return (rc); 3630Sstevel@tonic-gate } 3640Sstevel@tonic-gate 3650Sstevel@tonic-gate /* set all filters */ 3660Sstevel@tonic-gate if ((rc = ipgpc_filters_info(fn, arg)) != 0) { 3670Sstevel@tonic-gate return (rc); 3680Sstevel@tonic-gate } 3690Sstevel@tonic-gate return (0); 3700Sstevel@tonic-gate } 3710Sstevel@tonic-gate 3720Sstevel@tonic-gate /* 3730Sstevel@tonic-gate * ipgpc_invoke_action(aid, packet) 3740Sstevel@tonic-gate * 3750Sstevel@tonic-gate * packet processing function for ipgpc 3760Sstevel@tonic-gate * 3770Sstevel@tonic-gate * given packet the selector information is parsed and the classify 3780Sstevel@tonic-gate * function is called with those selectors. The classify function will 3790Sstevel@tonic-gate * return either a class or NULL, which represents a memory error and 3800Sstevel@tonic-gate * ENOMEM is returned. If the class returned is not NULL, the class and next 3810Sstevel@tonic-gate * action, associated with that class, are added to packet 3820Sstevel@tonic-gate */ 3830Sstevel@tonic-gate /* ARGSUSED */ 3840Sstevel@tonic-gate static int 3850Sstevel@tonic-gate ipgpc_invoke_action(ipp_action_id_t aid, ipp_packet_t *packet) 3860Sstevel@tonic-gate { 3870Sstevel@tonic-gate ipgpc_class_t *out_class; 3880Sstevel@tonic-gate hrtime_t start, end; 3890Sstevel@tonic-gate mblk_t *mp = NULL; 3900Sstevel@tonic-gate ip_priv_t *priv = NULL; 3910Sstevel@tonic-gate ill_t *ill = NULL; 3920Sstevel@tonic-gate ipha_t *ipha; 3930Sstevel@tonic-gate ip_proc_t callout_pos; 3940Sstevel@tonic-gate int af; 3950Sstevel@tonic-gate int rc; 3960Sstevel@tonic-gate ipgpc_packet_t pkt; 3970Sstevel@tonic-gate uint_t ill_idx; 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate /* extract packet data */ 4000Sstevel@tonic-gate mp = ipp_packet_get_data(packet); 4010Sstevel@tonic-gate ASSERT(mp != NULL); 4020Sstevel@tonic-gate 4030Sstevel@tonic-gate priv = (ip_priv_t *)ipp_packet_get_private(packet); 4040Sstevel@tonic-gate ASSERT(priv != NULL); 4050Sstevel@tonic-gate 4060Sstevel@tonic-gate callout_pos = priv->proc; 4070Sstevel@tonic-gate ill_idx = priv->ill_index; 4080Sstevel@tonic-gate 4090Sstevel@tonic-gate /* If we don't get an M_DATA, then return an error */ 4100Sstevel@tonic-gate if (mp->b_datap->db_type != M_DATA) { 4110Sstevel@tonic-gate if ((mp->b_cont != NULL) && 4120Sstevel@tonic-gate (mp->b_cont->b_datap->db_type == M_DATA)) { 4130Sstevel@tonic-gate mp = mp->b_cont; /* jump over the M_CTL into M_DATA */ 4140Sstevel@tonic-gate } else { 4150Sstevel@tonic-gate ipgpc0dbg(("ipgpc_invoke_action: no data\n")); 4160Sstevel@tonic-gate atomic_add_64(&ipgpc_epackets, 1); 4170Sstevel@tonic-gate return (EINVAL); 4180Sstevel@tonic-gate } 4190Sstevel@tonic-gate } 4200Sstevel@tonic-gate 4210Sstevel@tonic-gate /* 4220Sstevel@tonic-gate * Translate the callout_pos into the direction the packet is traveling 4230Sstevel@tonic-gate */ 4240Sstevel@tonic-gate if (callout_pos != IPP_LOCAL_IN) { 4250Sstevel@tonic-gate if (callout_pos & IPP_LOCAL_OUT) { 4260Sstevel@tonic-gate callout_pos = IPP_LOCAL_OUT; 4270Sstevel@tonic-gate } else if (callout_pos & IPP_FWD_IN) { 4280Sstevel@tonic-gate callout_pos = IPP_FWD_IN; 4290Sstevel@tonic-gate } else { /* IPP_FWD_OUT */ 4300Sstevel@tonic-gate callout_pos = IPP_FWD_OUT; 4310Sstevel@tonic-gate } 4320Sstevel@tonic-gate } 4330Sstevel@tonic-gate 4340Sstevel@tonic-gate /* parse the packet from the message block */ 4350Sstevel@tonic-gate ipha = (ipha_t *)mp->b_rptr; 4360Sstevel@tonic-gate /* Determine IP Header Version */ 4370Sstevel@tonic-gate if (IPH_HDR_VERSION(ipha) == IPV4_VERSION) { 4380Sstevel@tonic-gate parse_packet(&pkt, mp); 4390Sstevel@tonic-gate af = AF_INET; 4400Sstevel@tonic-gate } else { 4410Sstevel@tonic-gate parse_packet6(&pkt, mp); 4420Sstevel@tonic-gate af = AF_INET6; 4430Sstevel@tonic-gate } 4440Sstevel@tonic-gate 4450Sstevel@tonic-gate pkt.direction = callout_pos; /* set packet direction */ 4460Sstevel@tonic-gate 447*8485SPeter.Memishian@Sun.COM /* The ill_index could be 0 when called from forwarding (read) path */ 448*8485SPeter.Memishian@Sun.COM if (ill_idx > 0) { 449*8485SPeter.Memishian@Sun.COM ill = ill_lookup_on_ifindex_global_instance(ill_idx, B_FALSE, 450*8485SPeter.Memishian@Sun.COM NULL, NULL, NULL, NULL); 451*8485SPeter.Memishian@Sun.COM } 4520Sstevel@tonic-gate if (ill != NULL) { 453*8485SPeter.Memishian@Sun.COM /* 454*8485SPeter.Memishian@Sun.COM * Since all IPP actions in an IPMP group are performed 455*8485SPeter.Memishian@Sun.COM * relative to the IPMP group interface, if this is an 456*8485SPeter.Memishian@Sun.COM * underlying interface in an IPMP group, use the IPMP 457*8485SPeter.Memishian@Sun.COM * group interface's index. 458*8485SPeter.Memishian@Sun.COM */ 459*8485SPeter.Memishian@Sun.COM if (IS_UNDER_IPMP(ill)) 460*8485SPeter.Memishian@Sun.COM pkt.if_index = ipmp_ill_get_ipmp_ifindex(ill); 461*8485SPeter.Memishian@Sun.COM else 462*8485SPeter.Memishian@Sun.COM pkt.if_index = ill->ill_phyint->phyint_ifindex; 463*8485SPeter.Memishian@Sun.COM /* Got the field from the ILL, go ahead and refrele */ 4640Sstevel@tonic-gate ill_refrele(ill); 4650Sstevel@tonic-gate } else { 466*8485SPeter.Memishian@Sun.COM /* unknown if_index */ 4670Sstevel@tonic-gate pkt.if_index = IPGPC_UNSPECIFIED; 4680Sstevel@tonic-gate } 4690Sstevel@tonic-gate 4700Sstevel@tonic-gate if (ipgpc_debug > 5) { 4710Sstevel@tonic-gate /* print pkt under high debug level */ 4720Sstevel@tonic-gate #ifdef IPGPC_DEBUG 4730Sstevel@tonic-gate print_packet(af, &pkt); 4740Sstevel@tonic-gate #endif 4750Sstevel@tonic-gate } 4760Sstevel@tonic-gate if (ipgpc_debug > 3) { 4770Sstevel@tonic-gate start = gethrtime(); /* start timer */ 4780Sstevel@tonic-gate } 4790Sstevel@tonic-gate 4800Sstevel@tonic-gate /* classify this packet */ 4810Sstevel@tonic-gate out_class = ipgpc_classify(af, &pkt); 4820Sstevel@tonic-gate 4830Sstevel@tonic-gate if (ipgpc_debug > 3) { 4840Sstevel@tonic-gate end = gethrtime(); /* stop timer */ 4850Sstevel@tonic-gate } 4860Sstevel@tonic-gate 4870Sstevel@tonic-gate /* ipgpc_classify will only return NULL if a memory error occured */ 4880Sstevel@tonic-gate if (out_class == NULL) { 4890Sstevel@tonic-gate atomic_add_64(&ipgpc_epackets, 1); 4900Sstevel@tonic-gate return (ENOMEM); 4910Sstevel@tonic-gate } 4920Sstevel@tonic-gate 4930Sstevel@tonic-gate ipgpc1dbg(("ipgpc_invoke_action: class = %s", out_class->class_name)); 4940Sstevel@tonic-gate /* print time to classify(..) */ 4950Sstevel@tonic-gate ipgpc2dbg(("ipgpc_invoke_action: time = %lld nsec\n", (end - start))); 4960Sstevel@tonic-gate 4970Sstevel@tonic-gate if ((rc = ipp_packet_add_class(packet, out_class->class_name, 4980Sstevel@tonic-gate out_class->next_action)) != 0) { 4990Sstevel@tonic-gate atomic_add_64(&ipgpc_epackets, 1); 5000Sstevel@tonic-gate ipgpc0dbg(("ipgpc_invoke_action: ipp_packet_add_class " \ 5010Sstevel@tonic-gate "failed with error %d", rc)); 5020Sstevel@tonic-gate return (rc); 5030Sstevel@tonic-gate } 5040Sstevel@tonic-gate return (ipp_packet_next(packet, IPP_ACTION_CONT)); 5050Sstevel@tonic-gate } 506