17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5f4b3ec61Sdh155122 * Common Development and Distribution License (the "License"). 6f4b3ec61Sdh155122 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22e11c3f44Smeem * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include <sys/systm.h> 277c478bd9Sstevel@tonic-gate #include <sys/socket.h> 287c478bd9Sstevel@tonic-gate #include <netinet/in.h> 297c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 307c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 317c478bd9Sstevel@tonic-gate #include <ipp/ipp.h> 327c478bd9Sstevel@tonic-gate #include <ipp/ipp_config.h> 337c478bd9Sstevel@tonic-gate #include <ipp/ipgpc/classifier.h> 347c478bd9Sstevel@tonic-gate #include <inet/ip.h> 357c478bd9Sstevel@tonic-gate #include <net/if.h> 367c478bd9Sstevel@tonic-gate #include <inet/ip_if.h> 377c478bd9Sstevel@tonic-gate #include <inet/ipp_common.h> 387c478bd9Sstevel@tonic-gate 397c478bd9Sstevel@tonic-gate /* DDI file for ipgpc ipp module */ 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate /* protects against multiple configs */ 427c478bd9Sstevel@tonic-gate static kmutex_t ipgpc_config_lock; 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate static int ipgpc_create_action(ipp_action_id_t, nvlist_t **, ipp_flags_t); 457c478bd9Sstevel@tonic-gate static int ipgpc_modify_action(ipp_action_id_t, nvlist_t **, ipp_flags_t); 467c478bd9Sstevel@tonic-gate static int ipgpc_destroy_action(ipp_action_id_t, ipp_flags_t); 477c478bd9Sstevel@tonic-gate static int ipgpc_info(ipp_action_id_t aid, int (*)(nvlist_t *, void *), void *, 487c478bd9Sstevel@tonic-gate ipp_flags_t); 497c478bd9Sstevel@tonic-gate static int ipgpc_invoke_action(ipp_action_id_t, ipp_packet_t *); 507c478bd9Sstevel@tonic-gate 517c478bd9Sstevel@tonic-gate ipp_ops_t ipgpc_ops = { 527c478bd9Sstevel@tonic-gate IPPO_REV, 537c478bd9Sstevel@tonic-gate ipgpc_create_action, /* ippo_action_create */ 547c478bd9Sstevel@tonic-gate ipgpc_modify_action, /* ippo_action_modify */ 557c478bd9Sstevel@tonic-gate ipgpc_destroy_action, /* ippo_action_destroy */ 567c478bd9Sstevel@tonic-gate ipgpc_info, /* ippo_action_info */ 577c478bd9Sstevel@tonic-gate ipgpc_invoke_action /* ippo_action_invoke */ 587c478bd9Sstevel@tonic-gate }; 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate extern struct mod_ops mod_ippops; 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate /* 637c478bd9Sstevel@tonic-gate * Module linkage information for the kernel. 647c478bd9Sstevel@tonic-gate */ 657c478bd9Sstevel@tonic-gate static struct modlipp modlipp = { 667c478bd9Sstevel@tonic-gate &mod_ippops, 677c478bd9Sstevel@tonic-gate "IP Generic Packet Classifier (ipgpc) module 1.0", 687c478bd9Sstevel@tonic-gate &ipgpc_ops 697c478bd9Sstevel@tonic-gate }; 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 727c478bd9Sstevel@tonic-gate MODREV_1, 737c478bd9Sstevel@tonic-gate (void *)&modlipp, 747c478bd9Sstevel@tonic-gate NULL 757c478bd9Sstevel@tonic-gate }; 767c478bd9Sstevel@tonic-gate 777c478bd9Sstevel@tonic-gate #define __FN__ "_init" 787c478bd9Sstevel@tonic-gate int 797c478bd9Sstevel@tonic-gate _init( 807c478bd9Sstevel@tonic-gate void) 817c478bd9Sstevel@tonic-gate { 827c478bd9Sstevel@tonic-gate int rc; 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate if (ipgpc_action_exist) { 857c478bd9Sstevel@tonic-gate return (EBUSY); 867c478bd9Sstevel@tonic-gate } 877c478bd9Sstevel@tonic-gate /* init mutexes */ 887c478bd9Sstevel@tonic-gate mutex_init(&ipgpc_config_lock, NULL, MUTEX_DRIVER, NULL); 897c478bd9Sstevel@tonic-gate mutex_init(&ipgpc_fid_list_lock, NULL, MUTEX_DRIVER, NULL); 907c478bd9Sstevel@tonic-gate mutex_init(&ipgpc_cid_list_lock, NULL, MUTEX_DRIVER, NULL); 917c478bd9Sstevel@tonic-gate mutex_init(&ipgpc_table_list_lock, NULL, MUTEX_DRIVER, NULL); 927c478bd9Sstevel@tonic-gate mutex_init(&ipgpc_ds_table_id.lock, NULL, MUTEX_DRIVER, NULL); 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate if ((rc = mod_install(&modlinkage)) != 0) { 957c478bd9Sstevel@tonic-gate /* clean up after fail */ 967c478bd9Sstevel@tonic-gate mutex_destroy(&ipgpc_config_lock); 977c478bd9Sstevel@tonic-gate mutex_destroy(&ipgpc_fid_list_lock); 987c478bd9Sstevel@tonic-gate mutex_destroy(&ipgpc_cid_list_lock); 997c478bd9Sstevel@tonic-gate mutex_destroy(&ipgpc_table_list_lock); 1007c478bd9Sstevel@tonic-gate mutex_destroy(&ipgpc_ds_table_id.lock); 1017c478bd9Sstevel@tonic-gate } 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate return (rc); 1047c478bd9Sstevel@tonic-gate } 1057c478bd9Sstevel@tonic-gate #undef __FN__ 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate #define __FN__ "_fini" 1087c478bd9Sstevel@tonic-gate int 1097c478bd9Sstevel@tonic-gate _fini( 1107c478bd9Sstevel@tonic-gate void) 1117c478bd9Sstevel@tonic-gate { 1127c478bd9Sstevel@tonic-gate int rc; 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate if (ipgpc_action_exist) { 1157c478bd9Sstevel@tonic-gate return (EBUSY); 1167c478bd9Sstevel@tonic-gate } 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate if ((rc = mod_remove(&modlinkage)) != 0) { 1197c478bd9Sstevel@tonic-gate return (rc); 1207c478bd9Sstevel@tonic-gate } 1217c478bd9Sstevel@tonic-gate /* destroy mutexes */ 1227c478bd9Sstevel@tonic-gate mutex_destroy(&ipgpc_config_lock); 1237c478bd9Sstevel@tonic-gate mutex_destroy(&ipgpc_fid_list_lock); 1247c478bd9Sstevel@tonic-gate mutex_destroy(&ipgpc_cid_list_lock); 1257c478bd9Sstevel@tonic-gate mutex_destroy(&ipgpc_table_list_lock); 1267c478bd9Sstevel@tonic-gate mutex_destroy(&ipgpc_ds_table_id.lock); 1277c478bd9Sstevel@tonic-gate return (rc); 1287c478bd9Sstevel@tonic-gate } 1297c478bd9Sstevel@tonic-gate #undef __FN__ 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate #define __FN__ "_info" 1327c478bd9Sstevel@tonic-gate int 1337c478bd9Sstevel@tonic-gate _info( 1347c478bd9Sstevel@tonic-gate struct modinfo *modinfop) 1357c478bd9Sstevel@tonic-gate { 1367c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1377c478bd9Sstevel@tonic-gate } 1387c478bd9Sstevel@tonic-gate #undef __FN__ 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate /* 1417c478bd9Sstevel@tonic-gate * ipgpc_create_action(aid, nvlpp, flags) 1427c478bd9Sstevel@tonic-gate * 1437c478bd9Sstevel@tonic-gate * creates a single instance of ipgpc, if one does not exist. If an action 1447c478bd9Sstevel@tonic-gate * instance already exists, fail with EBUSY 1457c478bd9Sstevel@tonic-gate * 1467c478bd9Sstevel@tonic-gate * if nvlpp contains the name IPP_ACTION_STATS_ENABLE, then process it and 1477c478bd9Sstevel@tonic-gate * determine if global stats should be collected 1487c478bd9Sstevel@tonic-gate * 1497c478bd9Sstevel@tonic-gate * the ipgpc_config_lock is taken to block out any other creates or destroys 1507c478bd9Sstevel@tonic-gate * the are issued while the create is taking place 1517c478bd9Sstevel@tonic-gate */ 1527c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1537c478bd9Sstevel@tonic-gate static int 1547c478bd9Sstevel@tonic-gate ipgpc_create_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags) 1557c478bd9Sstevel@tonic-gate { 1567c478bd9Sstevel@tonic-gate int rc; 1577c478bd9Sstevel@tonic-gate uint32_t stat; 1587c478bd9Sstevel@tonic-gate nvlist_t *nvlp; 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate nvlp = *nvlpp; 1617c478bd9Sstevel@tonic-gate *nvlpp = NULL; /* nvlist should be NULL when this returns */ 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate /* only one ipgpc action instance can be loaded at once */ 1647c478bd9Sstevel@tonic-gate if (ipgpc_action_exist) { 1657c478bd9Sstevel@tonic-gate nvlist_free(nvlp); 1667c478bd9Sstevel@tonic-gate return (EBUSY); 1677c478bd9Sstevel@tonic-gate } else { 1687c478bd9Sstevel@tonic-gate mutex_enter(&ipgpc_config_lock); 1697c478bd9Sstevel@tonic-gate if (ipgpc_action_exist) { 1707c478bd9Sstevel@tonic-gate nvlist_free(nvlp); 1717c478bd9Sstevel@tonic-gate mutex_exit(&ipgpc_config_lock); 1727c478bd9Sstevel@tonic-gate return (EBUSY); 1737c478bd9Sstevel@tonic-gate } 1747c478bd9Sstevel@tonic-gate /* check for action param IPP_ACTION_STATS_ENABLE */ 1757c478bd9Sstevel@tonic-gate if ((rc = nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE, 1767c478bd9Sstevel@tonic-gate &stat)) != 0) { 1777c478bd9Sstevel@tonic-gate ipgpc_gather_stats = B_FALSE; /* disabled by default */ 1787c478bd9Sstevel@tonic-gate } else { 1797c478bd9Sstevel@tonic-gate ipgpc_gather_stats = (boolean_t)stat; 1807c478bd9Sstevel@tonic-gate } 1817c478bd9Sstevel@tonic-gate if ((rc = ipgpc_initialize(aid)) != 0) { 1827c478bd9Sstevel@tonic-gate ipgpc0dbg(("ipgpc_create_action: ipgpc_intialize " \ 1837c478bd9Sstevel@tonic-gate "error %d", rc)); 1847c478bd9Sstevel@tonic-gate ipgpc_destroy(IPP_DESTROY_REF); 1857c478bd9Sstevel@tonic-gate ipgpc_action_exist = B_FALSE; 1867c478bd9Sstevel@tonic-gate nvlist_free(nvlp); 1877c478bd9Sstevel@tonic-gate mutex_exit(&ipgpc_config_lock); 1887c478bd9Sstevel@tonic-gate return (rc); 1897c478bd9Sstevel@tonic-gate } 1907c478bd9Sstevel@tonic-gate ipgpc_action_exist = B_TRUE; 1917c478bd9Sstevel@tonic-gate nvlist_free(nvlp); 1927c478bd9Sstevel@tonic-gate mutex_exit(&ipgpc_config_lock); 1937c478bd9Sstevel@tonic-gate return (0); 1947c478bd9Sstevel@tonic-gate } 1957c478bd9Sstevel@tonic-gate } 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate /* 1987c478bd9Sstevel@tonic-gate * ipgpc_modify_action 1997c478bd9Sstevel@tonic-gate * 2007c478bd9Sstevel@tonic-gate * modify an instance of ipgpc 2017c478bd9Sstevel@tonic-gate * 2027c478bd9Sstevel@tonic-gate * nvlpp will contain the configuration type to switch off of. Use this 2037c478bd9Sstevel@tonic-gate * to determine what modification should be made. If the modification fails, 2047c478bd9Sstevel@tonic-gate * return the appropriate error. 2057c478bd9Sstevel@tonic-gate */ 2067c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2077c478bd9Sstevel@tonic-gate static int 2087c478bd9Sstevel@tonic-gate ipgpc_modify_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags) 2097c478bd9Sstevel@tonic-gate { 2107c478bd9Sstevel@tonic-gate nvlist_t *nvlp; 2117c478bd9Sstevel@tonic-gate int rc = 0; 2127c478bd9Sstevel@tonic-gate uint8_t config_type; 2137c478bd9Sstevel@tonic-gate uint32_t stat; 2147c478bd9Sstevel@tonic-gate char *name; 2157c478bd9Sstevel@tonic-gate int32_t filter_instance; 2167c478bd9Sstevel@tonic-gate ipgpc_filter_t *filter; 2177c478bd9Sstevel@tonic-gate ipgpc_class_t *aclass; 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate nvlp = *nvlpp; 2207c478bd9Sstevel@tonic-gate *nvlpp = NULL; /* nvlist should be NULL when this returns */ 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate if ((rc = nvlist_lookup_byte(nvlp, IPP_CONFIG_TYPE, &config_type)) 2237c478bd9Sstevel@tonic-gate != 0) { 2247c478bd9Sstevel@tonic-gate nvlist_free(nvlp); 2257c478bd9Sstevel@tonic-gate ipgpc0dbg(("ipgpc_modify_action: invalid configuration type")); 2267c478bd9Sstevel@tonic-gate return (EINVAL); 2277c478bd9Sstevel@tonic-gate } 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate switch (config_type) { 2307c478bd9Sstevel@tonic-gate case IPP_SET: /* set an action parameter */ 2317c478bd9Sstevel@tonic-gate if ((rc = nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE, 2327c478bd9Sstevel@tonic-gate &stat)) != 0) { 2337c478bd9Sstevel@tonic-gate nvlist_free(nvlp); 2347c478bd9Sstevel@tonic-gate ipgpc0dbg(("ipgpc_modify_action: invalid IPP_SET " \ 2357c478bd9Sstevel@tonic-gate "parameter")); 2367c478bd9Sstevel@tonic-gate return (EINVAL); 2377c478bd9Sstevel@tonic-gate } else { 2387c478bd9Sstevel@tonic-gate ipgpc_gather_stats = (boolean_t)stat; 2397c478bd9Sstevel@tonic-gate } 2407c478bd9Sstevel@tonic-gate break; 2417c478bd9Sstevel@tonic-gate case CLASSIFIER_ADD_FILTER: /* add a filter */ 2427c478bd9Sstevel@tonic-gate filter = kmem_zalloc(sizeof (ipgpc_filter_t), KM_SLEEP); 2437c478bd9Sstevel@tonic-gate if ((rc = ipgpc_parse_filter(filter, nvlp)) != 0) { 2447c478bd9Sstevel@tonic-gate ipgpc0dbg(("ipgpc_modify_action: invalid filter")); 2457c478bd9Sstevel@tonic-gate ipgpc_filter_destructor(filter); 2467c478bd9Sstevel@tonic-gate kmem_free(filter, sizeof (ipgpc_filter_t)); 2477c478bd9Sstevel@tonic-gate break; 2487c478bd9Sstevel@tonic-gate } 2497c478bd9Sstevel@tonic-gate /* parse class name */ 2507c478bd9Sstevel@tonic-gate if ((rc = nvlist_lookup_string(nvlp, CLASSIFIER_CLASS_NAME, 2517c478bd9Sstevel@tonic-gate &name)) != 0) { 2527c478bd9Sstevel@tonic-gate ipgpc0dbg(("ipgpc_modify_action: class name missing")); 2537c478bd9Sstevel@tonic-gate ipgpc_filter_destructor(filter); 2547c478bd9Sstevel@tonic-gate kmem_free(filter, sizeof (ipgpc_filter_t)); 2557c478bd9Sstevel@tonic-gate break; 2567c478bd9Sstevel@tonic-gate } 2577c478bd9Sstevel@tonic-gate rc = ipgpc_addfilter(filter, name, flags); 2587c478bd9Sstevel@tonic-gate if (rc != 0) { 2597c478bd9Sstevel@tonic-gate ipgpc_filter_destructor(filter); 2607c478bd9Sstevel@tonic-gate } 2617c478bd9Sstevel@tonic-gate kmem_free(filter, sizeof (ipgpc_filter_t)); 2627c478bd9Sstevel@tonic-gate break; 2637c478bd9Sstevel@tonic-gate case CLASSIFIER_ADD_CLASS: /* add a class */ 2647c478bd9Sstevel@tonic-gate aclass = kmem_zalloc(sizeof (ipgpc_class_t), KM_SLEEP); 2657c478bd9Sstevel@tonic-gate if ((rc = ipgpc_parse_class(aclass, nvlp)) != 0) { 2667c478bd9Sstevel@tonic-gate ipgpc0dbg(("ipgpc_modify_action: invalid class")); 2677c478bd9Sstevel@tonic-gate kmem_free(aclass, sizeof (ipgpc_class_t)); 2687c478bd9Sstevel@tonic-gate break; 2697c478bd9Sstevel@tonic-gate } 2707c478bd9Sstevel@tonic-gate rc = ipgpc_addclass(aclass, flags); 2717c478bd9Sstevel@tonic-gate kmem_free(aclass, sizeof (ipgpc_class_t)); 2727c478bd9Sstevel@tonic-gate break; 2737c478bd9Sstevel@tonic-gate case CLASSIFIER_REMOVE_FILTER: /* remove a filter */ 2747c478bd9Sstevel@tonic-gate /* parse filter name */ 2757c478bd9Sstevel@tonic-gate if ((rc = nvlist_lookup_string(nvlp, CLASSIFIER_FILTER_NAME, 2767c478bd9Sstevel@tonic-gate &name)) != 0) { 2777c478bd9Sstevel@tonic-gate ipgpc0dbg(("ipgpc_modify_action: filtername missing")); 2787c478bd9Sstevel@tonic-gate break; 2797c478bd9Sstevel@tonic-gate } 2807c478bd9Sstevel@tonic-gate /* parse optional filter_instance */ 2817c478bd9Sstevel@tonic-gate if (nvlist_lookup_int32(nvlp, IPGPC_FILTER_INSTANCE, 2827c478bd9Sstevel@tonic-gate &filter_instance) != 0) { 2837c478bd9Sstevel@tonic-gate filter_instance = -1; 2847c478bd9Sstevel@tonic-gate } 2857c478bd9Sstevel@tonic-gate rc = ipgpc_removefilter(name, filter_instance, flags); 2867c478bd9Sstevel@tonic-gate break; 2877c478bd9Sstevel@tonic-gate case CLASSIFIER_REMOVE_CLASS: /* remove a class */ 2887c478bd9Sstevel@tonic-gate /* parse class name */ 2897c478bd9Sstevel@tonic-gate if ((rc = nvlist_lookup_string(nvlp, CLASSIFIER_CLASS_NAME, 2907c478bd9Sstevel@tonic-gate &name)) != 0) { 2917c478bd9Sstevel@tonic-gate ipgpc0dbg(("ipgpc_modify_action: class name missing")); 2927c478bd9Sstevel@tonic-gate break; 2937c478bd9Sstevel@tonic-gate } 2947c478bd9Sstevel@tonic-gate rc = ipgpc_removeclass(name, flags); 2957c478bd9Sstevel@tonic-gate break; 2967c478bd9Sstevel@tonic-gate case CLASSIFIER_MODIFY_FILTER: /* modify a filter */ 2977c478bd9Sstevel@tonic-gate rc = ipgpc_modifyfilter(&nvlp, flags); 2987c478bd9Sstevel@tonic-gate break; 2997c478bd9Sstevel@tonic-gate case CLASSIFIER_MODIFY_CLASS: /* modify a class */ 3007c478bd9Sstevel@tonic-gate rc = ipgpc_modifyclass(&nvlp, flags); 3017c478bd9Sstevel@tonic-gate break; 3027c478bd9Sstevel@tonic-gate default: /* invalid config type */ 3037c478bd9Sstevel@tonic-gate nvlist_free(nvlp); 3047c478bd9Sstevel@tonic-gate ipgpc0dbg(("ipgpc_modify_action:invalid configuration type %u", 3057c478bd9Sstevel@tonic-gate config_type)); 3067c478bd9Sstevel@tonic-gate return (EINVAL); 3077c478bd9Sstevel@tonic-gate } 3087c478bd9Sstevel@tonic-gate nvlist_free(nvlp); /* free the list */ 3097c478bd9Sstevel@tonic-gate return (rc); /* nvlist is passed back NULL */ 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate /* 3137c478bd9Sstevel@tonic-gate * ipgpc_destroy_action(aid, flags) 3147c478bd9Sstevel@tonic-gate * 3157c478bd9Sstevel@tonic-gate * action destructor for ipgpc 3167c478bd9Sstevel@tonic-gate * 3177c478bd9Sstevel@tonic-gate * Destroys an instance of the ipgpc action, if one exists. The 3187c478bd9Sstevel@tonic-gate * ipgpc_action_lock is taken to block out any other destroys or creates 3197c478bd9Sstevel@tonic-gate * that might be issued while the action is being destroyed 3207c478bd9Sstevel@tonic-gate */ 3217c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3227c478bd9Sstevel@tonic-gate static int 3237c478bd9Sstevel@tonic-gate ipgpc_destroy_action(ipp_action_id_t aid, ipp_flags_t flags) 3247c478bd9Sstevel@tonic-gate { 3257c478bd9Sstevel@tonic-gate /* only destroy action if it exists */ 3267c478bd9Sstevel@tonic-gate if (ipgpc_action_exist == B_TRUE) { 3277c478bd9Sstevel@tonic-gate mutex_enter(&ipgpc_config_lock); 3287c478bd9Sstevel@tonic-gate if (ipgpc_action_exist == B_FALSE) { 3297c478bd9Sstevel@tonic-gate mutex_exit(&ipgpc_config_lock); 3307c478bd9Sstevel@tonic-gate return (EBUSY); 3317c478bd9Sstevel@tonic-gate } 3327c478bd9Sstevel@tonic-gate ipgpc_action_exist = B_FALSE; 3337c478bd9Sstevel@tonic-gate ipgpc_destroy(flags); 3347c478bd9Sstevel@tonic-gate mutex_exit(&ipgpc_config_lock); 3357c478bd9Sstevel@tonic-gate } 3367c478bd9Sstevel@tonic-gate return (0); 3377c478bd9Sstevel@tonic-gate } 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate /* 3407c478bd9Sstevel@tonic-gate * ipgpc_info(aid, fn, arg) 3417c478bd9Sstevel@tonic-gate * 3427c478bd9Sstevel@tonic-gate * configuration quering function for ipgpc 3437c478bd9Sstevel@tonic-gate * 3447c478bd9Sstevel@tonic-gate * passes back the configuration of ipgpc through allocated nvlists 3457c478bd9Sstevel@tonic-gate * all action paramaters, classes and filters are built into nvlists 3467c478bd9Sstevel@tonic-gate * and passed to the function pointer fn with arg 3477c478bd9Sstevel@tonic-gate */ 3487c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3497c478bd9Sstevel@tonic-gate static int 3507c478bd9Sstevel@tonic-gate ipgpc_info(ipp_action_id_t aid, int (*fn)(nvlist_t *, void *), void *arg, 3517c478bd9Sstevel@tonic-gate ipp_flags_t flags) 3527c478bd9Sstevel@tonic-gate { 3537c478bd9Sstevel@tonic-gate int rc; 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate /* set parameters */ 3567c478bd9Sstevel@tonic-gate if ((rc = ipgpc_params_info(fn, arg)) != 0) { 3577c478bd9Sstevel@tonic-gate return (rc); 3587c478bd9Sstevel@tonic-gate } 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate /* set all classes */ 3617c478bd9Sstevel@tonic-gate if ((rc = ipgpc_classes_info(fn, arg)) != 0) { 3627c478bd9Sstevel@tonic-gate return (rc); 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate /* set all filters */ 3667c478bd9Sstevel@tonic-gate if ((rc = ipgpc_filters_info(fn, arg)) != 0) { 3677c478bd9Sstevel@tonic-gate return (rc); 3687c478bd9Sstevel@tonic-gate } 3697c478bd9Sstevel@tonic-gate return (0); 3707c478bd9Sstevel@tonic-gate } 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate /* 3737c478bd9Sstevel@tonic-gate * ipgpc_invoke_action(aid, packet) 3747c478bd9Sstevel@tonic-gate * 3757c478bd9Sstevel@tonic-gate * packet processing function for ipgpc 3767c478bd9Sstevel@tonic-gate * 3777c478bd9Sstevel@tonic-gate * given packet the selector information is parsed and the classify 3787c478bd9Sstevel@tonic-gate * function is called with those selectors. The classify function will 3797c478bd9Sstevel@tonic-gate * return either a class or NULL, which represents a memory error and 3807c478bd9Sstevel@tonic-gate * ENOMEM is returned. If the class returned is not NULL, the class and next 3817c478bd9Sstevel@tonic-gate * action, associated with that class, are added to packet 3827c478bd9Sstevel@tonic-gate */ 3837c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3847c478bd9Sstevel@tonic-gate static int 3857c478bd9Sstevel@tonic-gate ipgpc_invoke_action(ipp_action_id_t aid, ipp_packet_t *packet) 3867c478bd9Sstevel@tonic-gate { 3877c478bd9Sstevel@tonic-gate ipgpc_class_t *out_class; 3887c478bd9Sstevel@tonic-gate hrtime_t start, end; 3897c478bd9Sstevel@tonic-gate mblk_t *mp = NULL; 3907c478bd9Sstevel@tonic-gate ip_priv_t *priv = NULL; 3917c478bd9Sstevel@tonic-gate ill_t *ill = NULL; 3927c478bd9Sstevel@tonic-gate ipha_t *ipha; 3937c478bd9Sstevel@tonic-gate ip_proc_t callout_pos; 3947c478bd9Sstevel@tonic-gate int af; 3957c478bd9Sstevel@tonic-gate int rc; 3967c478bd9Sstevel@tonic-gate ipgpc_packet_t pkt; 3977c478bd9Sstevel@tonic-gate uint_t ill_idx; 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate /* extract packet data */ 4007c478bd9Sstevel@tonic-gate mp = ipp_packet_get_data(packet); 4017c478bd9Sstevel@tonic-gate ASSERT(mp != NULL); 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate priv = (ip_priv_t *)ipp_packet_get_private(packet); 4047c478bd9Sstevel@tonic-gate ASSERT(priv != NULL); 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate callout_pos = priv->proc; 4077c478bd9Sstevel@tonic-gate ill_idx = priv->ill_index; 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate /* If we don't get an M_DATA, then return an error */ 4107c478bd9Sstevel@tonic-gate if (mp->b_datap->db_type != M_DATA) { 4117c478bd9Sstevel@tonic-gate if ((mp->b_cont != NULL) && 4127c478bd9Sstevel@tonic-gate (mp->b_cont->b_datap->db_type == M_DATA)) { 4137c478bd9Sstevel@tonic-gate mp = mp->b_cont; /* jump over the M_CTL into M_DATA */ 4147c478bd9Sstevel@tonic-gate } else { 4157c478bd9Sstevel@tonic-gate ipgpc0dbg(("ipgpc_invoke_action: no data\n")); 416*1a5e258fSJosef 'Jeff' Sipek atomic_inc_64(&ipgpc_epackets); 4177c478bd9Sstevel@tonic-gate return (EINVAL); 4187c478bd9Sstevel@tonic-gate } 4197c478bd9Sstevel@tonic-gate } 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate /* 4227c478bd9Sstevel@tonic-gate * Translate the callout_pos into the direction the packet is traveling 4237c478bd9Sstevel@tonic-gate */ 4247c478bd9Sstevel@tonic-gate if (callout_pos != IPP_LOCAL_IN) { 4257c478bd9Sstevel@tonic-gate if (callout_pos & IPP_LOCAL_OUT) { 4267c478bd9Sstevel@tonic-gate callout_pos = IPP_LOCAL_OUT; 4277c478bd9Sstevel@tonic-gate } else if (callout_pos & IPP_FWD_IN) { 4287c478bd9Sstevel@tonic-gate callout_pos = IPP_FWD_IN; 4297c478bd9Sstevel@tonic-gate } else { /* IPP_FWD_OUT */ 4307c478bd9Sstevel@tonic-gate callout_pos = IPP_FWD_OUT; 4317c478bd9Sstevel@tonic-gate } 4327c478bd9Sstevel@tonic-gate } 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate /* parse the packet from the message block */ 4357c478bd9Sstevel@tonic-gate ipha = (ipha_t *)mp->b_rptr; 4367c478bd9Sstevel@tonic-gate /* Determine IP Header Version */ 4377c478bd9Sstevel@tonic-gate if (IPH_HDR_VERSION(ipha) == IPV4_VERSION) { 4387c478bd9Sstevel@tonic-gate parse_packet(&pkt, mp); 4397c478bd9Sstevel@tonic-gate af = AF_INET; 4407c478bd9Sstevel@tonic-gate } else { 4417c478bd9Sstevel@tonic-gate parse_packet6(&pkt, mp); 4427c478bd9Sstevel@tonic-gate af = AF_INET6; 4437c478bd9Sstevel@tonic-gate } 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate pkt.direction = callout_pos; /* set packet direction */ 4467c478bd9Sstevel@tonic-gate 447e11c3f44Smeem /* The ill_index could be 0 when called from forwarding (read) path */ 448bd670b35SErik Nordmark if (ill_idx > 0) 449bd670b35SErik Nordmark ill = ill_lookup_on_ifindex_global_instance(ill_idx, B_FALSE); 450bd670b35SErik Nordmark 451e11c3f44Smeem if (ill != NULL) { 452e11c3f44Smeem /* 453e11c3f44Smeem * Since all IPP actions in an IPMP group are performed 454e11c3f44Smeem * relative to the IPMP group interface, if this is an 455e11c3f44Smeem * underlying interface in an IPMP group, use the IPMP 456e11c3f44Smeem * group interface's index. 457e11c3f44Smeem */ 458e11c3f44Smeem if (IS_UNDER_IPMP(ill)) 459e11c3f44Smeem pkt.if_index = ipmp_ill_get_ipmp_ifindex(ill); 460e11c3f44Smeem else 461e11c3f44Smeem pkt.if_index = ill->ill_phyint->phyint_ifindex; 462e11c3f44Smeem /* Got the field from the ILL, go ahead and refrele */ 4637c478bd9Sstevel@tonic-gate ill_refrele(ill); 4647c478bd9Sstevel@tonic-gate } else { 465e11c3f44Smeem /* unknown if_index */ 4667c478bd9Sstevel@tonic-gate pkt.if_index = IPGPC_UNSPECIFIED; 4677c478bd9Sstevel@tonic-gate } 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate if (ipgpc_debug > 5) { 4707c478bd9Sstevel@tonic-gate /* print pkt under high debug level */ 4717c478bd9Sstevel@tonic-gate #ifdef IPGPC_DEBUG 4727c478bd9Sstevel@tonic-gate print_packet(af, &pkt); 4737c478bd9Sstevel@tonic-gate #endif 4747c478bd9Sstevel@tonic-gate } 4757c478bd9Sstevel@tonic-gate if (ipgpc_debug > 3) { 4767c478bd9Sstevel@tonic-gate start = gethrtime(); /* start timer */ 4777c478bd9Sstevel@tonic-gate } 4787c478bd9Sstevel@tonic-gate 4797c478bd9Sstevel@tonic-gate /* classify this packet */ 4807c478bd9Sstevel@tonic-gate out_class = ipgpc_classify(af, &pkt); 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate if (ipgpc_debug > 3) { 4837c478bd9Sstevel@tonic-gate end = gethrtime(); /* stop timer */ 4847c478bd9Sstevel@tonic-gate } 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate /* ipgpc_classify will only return NULL if a memory error occured */ 4877c478bd9Sstevel@tonic-gate if (out_class == NULL) { 488*1a5e258fSJosef 'Jeff' Sipek atomic_inc_64(&ipgpc_epackets); 4897c478bd9Sstevel@tonic-gate return (ENOMEM); 4907c478bd9Sstevel@tonic-gate } 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate ipgpc1dbg(("ipgpc_invoke_action: class = %s", out_class->class_name)); 4937c478bd9Sstevel@tonic-gate /* print time to classify(..) */ 4947c478bd9Sstevel@tonic-gate ipgpc2dbg(("ipgpc_invoke_action: time = %lld nsec\n", (end - start))); 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate if ((rc = ipp_packet_add_class(packet, out_class->class_name, 4977c478bd9Sstevel@tonic-gate out_class->next_action)) != 0) { 498*1a5e258fSJosef 'Jeff' Sipek atomic_inc_64(&ipgpc_epackets); 4997c478bd9Sstevel@tonic-gate ipgpc0dbg(("ipgpc_invoke_action: ipp_packet_add_class " \ 5007c478bd9Sstevel@tonic-gate "failed with error %d", rc)); 5017c478bd9Sstevel@tonic-gate return (rc); 5027c478bd9Sstevel@tonic-gate } 5037c478bd9Sstevel@tonic-gate return (ipp_packet_next(packet, IPP_ACTION_CONT)); 5047c478bd9Sstevel@tonic-gate } 505