view usr/src/uts/common/inet/ip/ip_tunables.c @ 14115:417f3f83e896

3925 IP DCE does not scale Reviewed by: Keith M Wesolowski <wesolows@foobazco.org> Reviewed by: Theo Schlossnagle <jesus@omniti.com> Reviewed by: Sebastien Roy <seb@delphix.com> Approved by: Dan McDonald <danmcd@nexenta.com>
author Jerry Jelinek <jerry.jelinek@joyent.com>
date Mon, 13 Feb 2012 19:50:26 +0000
parents f0150cf47680
children
line wrap: on
line source

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
 * Copyright (c) 2013 by Delphix. All rights reserved.
 * Copyright (c) 2012, Joyent, Inc. All rights reserved.
 */
/* Copyright (c) 1990 Mentat Inc. */

#include <inet/ip.h>
#include <inet/ip6.h>
#include <inet/ip_if.h>
#include <inet/ip_ire.h>
#include <inet/ipclassifier.h>
#include <inet/ip_impl.h>
#include <inet/tunables.h>
#include <sys/sunddi.h>
#include <sys/policy.h>

/* How long, in seconds, we allow frags to hang around. */
#define	IP_REASM_TIMEOUT	15
#define	IPV6_REASM_TIMEOUT	60

/*
 * Set ip{,6}_forwarding values. If the value is being set on an ill,
 * find the ill and set the value on it. On the other hand if we are modifying
 * global property, modify the global value and set the value on all the ills.
 */
/* ARGSUSED */
static int
ip_set_forwarding(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
    const char *ifname, const void* pval, uint_t flags)
{
	char			*end;
	unsigned long		new_value;
	boolean_t		per_ill, isv6;
	ill_walk_context_t	ctx;
	ill_t			*ill;
	ip_stack_t		*ipst = stack->netstack_ip;

	if (flags & MOD_PROP_DEFAULT) {
		new_value = pinfo->prop_def_bval;
	} else {
		if (ddi_strtoul(pval, &end, 10, &new_value) != 0 ||
		    *end != '\0')
			return (EINVAL);
		if (new_value != B_TRUE && new_value != B_FALSE)
			return (EINVAL);
	}

	per_ill = (ifname != NULL && ifname[0] != '\0');
	/*
	 * if it's not per ill then set the global property and bring all the
	 * ills up to date with the new global value.
	 */
	if (!per_ill)
		pinfo->prop_cur_bval = (new_value == 1 ? B_TRUE : B_FALSE);

	isv6 = (pinfo->mpi_proto == MOD_PROTO_IPV6 ? B_TRUE : B_FALSE);
	rw_enter(&ipst->ips_ill_g_lock, RW_READER);
	if (isv6)
		ill = ILL_START_WALK_V6(&ctx, ipst);
	else
		ill = ILL_START_WALK_V4(&ctx, ipst);

	for (; ill != NULL; ill = ill_next(&ctx, ill)) {
		/*
		 * if the property needs to be set on a particular
		 * interface, look for that interface.
		 */
		if (per_ill && strcmp(ifname, ill->ill_name) != 0)
			continue;
		(void) ill_forward_set(ill, new_value != 0);
	}
	rw_exit(&ipst->ips_ill_g_lock);

	return (0);
}

static int
ip_get_forwarding(netstack_t *stack, mod_prop_info_t *pinfo, const char *ifname,
    void *pval, uint_t pr_size, uint_t flags)
{
	boolean_t		value;
	ill_walk_context_t	ctx;
	ill_t			*ill;
	ip_stack_t		*ipst = stack->netstack_ip;
	boolean_t		get_def = (flags & MOD_PROP_DEFAULT);
	boolean_t		get_perm = (flags & MOD_PROP_PERM);
	boolean_t		isv6;
	size_t			nbytes = 0;

	if (get_perm) {
		nbytes = snprintf(pval, pr_size, "%d", MOD_PROP_PERM_RW);
		goto ret;
	} else if (get_def) {
		nbytes = snprintf(pval, pr_size, "%d", pinfo->prop_def_bval);
		goto ret;
	}

	/*
	 * if per interface value is not asked for return the current
	 * global value
	 */
	if (ifname == NULL || ifname[0] == '\0') {
		nbytes = snprintf(pval, pr_size, "%d", pinfo->prop_cur_bval);
		goto ret;
	}

	isv6 = (pinfo->mpi_proto == MOD_PROTO_IPV6 ? B_TRUE : B_FALSE);
	rw_enter(&ipst->ips_ill_g_lock, RW_READER);
	if (isv6)
		ill = ILL_START_WALK_V6(&ctx, ipst);
	else
		ill = ILL_START_WALK_V4(&ctx, ipst);
	for (; ill != NULL; ill = ill_next(&ctx, ill)) {
		/*
		 * if the property needs to be obtained on a particular
		 * interface, look for that interface.
		 */
		if (strcmp(ifname, ill->ill_name) == 0)
			break;
	}
	if (ill == NULL) {
		rw_exit(&ipst->ips_ill_g_lock);
		return (ENXIO);
	}
	value = ((ill->ill_flags & ILLF_ROUTER) ? B_TRUE : B_FALSE);
	rw_exit(&ipst->ips_ill_g_lock);
	nbytes = snprintf(pval, pr_size, "%d", value);
ret:
	if (nbytes >= pr_size)
		return (ENOBUFS);
	return (0);
}

/*
 * `ip_debug' is a global variable. So, we will be modifying the global
 * variable here.
 */
/* ARGSUSED */
int
ip_set_debug(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
    const char *ifname, const void* pval, uint_t flags)
{
	unsigned long	new_value;
	int		err;

	if (cr != NULL && secpolicy_net_config(cr, B_FALSE) != 0)
		return (EPERM);

	if ((err = mod_uint32_value(pval, pinfo, flags, &new_value)) != 0)
		return (err);
	ip_debug = (uint32_t)new_value;
	return (0);
}

/*
 * ip_debug is a global property. For default, permission and value range
 * we retrieve the value from `pinfo'. However for the current value we
 * retrieve the value from the global variable `ip_debug'
 */
/* ARGSUSED */
int
ip_get_debug(netstack_t *stack, mod_prop_info_t *pinfo, const char *ifname,
    void *pval, uint_t psize, uint_t flags)
{
	boolean_t	get_def = (flags & MOD_PROP_DEFAULT);
	boolean_t	get_perm = (flags & MOD_PROP_PERM);
	boolean_t	get_range = (flags & MOD_PROP_POSSIBLE);
	size_t		nbytes;

	bzero(pval, psize);
	if (get_perm)
		nbytes = snprintf(pval, psize, "%u", MOD_PROP_PERM_RW);
	else if (get_range)
		nbytes = snprintf(pval, psize, "%u-%u",
		    pinfo->prop_min_uval, pinfo->prop_max_uval);
	else if (get_def)
		nbytes = snprintf(pval, psize, "%u", pinfo->prop_def_uval);
	else
		nbytes = snprintf(pval, psize, "%u", ip_debug);
	if (nbytes >= psize)
		return (ENOBUFS);
	return (0);
}

/*
 * Set the CGTP (multirouting) filtering status. If the status is changed
 * from active to transparent or from transparent to active, forward the
 * new status to the filtering module (if loaded).
 */
/* ARGSUSED */
static int
ip_set_cgtp_filter(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
    const char *ifname, const void* pval, uint_t flags)
{
	unsigned long	new_value;
	ip_stack_t	*ipst = stack->netstack_ip;
	char		*end;

	if (flags & MOD_PROP_DEFAULT) {
		new_value = pinfo->prop_def_bval;
	} else {
		if (ddi_strtoul(pval, &end, 10, &new_value) != 0 ||
		    *end != '\0' || new_value > 1) {
			return (EINVAL);
		}
	}
	if (!pinfo->prop_cur_bval && new_value) {
		cmn_err(CE_NOTE, "IP: enabling CGTP filtering%s",
		    ipst->ips_ip_cgtp_filter_ops == NULL ?
		    " (module not loaded)" : "");
	}
	if (pinfo->prop_cur_bval && !new_value) {
		cmn_err(CE_NOTE, "IP: disabling CGTP filtering%s",
		    ipst->ips_ip_cgtp_filter_ops == NULL ?
		    " (module not loaded)" : "");
	}
	if (ipst->ips_ip_cgtp_filter_ops != NULL) {
		int	res;
		netstackid_t stackid = ipst->ips_netstack->netstack_stackid;

		res = ipst->ips_ip_cgtp_filter_ops->cfo_change_state(stackid,
		    new_value);
		if (res)
			return (res);
	}
	pinfo->prop_cur_bval = (new_value == 1 ? B_TRUE : B_FALSE);
	ill_set_inputfn_all(ipst);
	return (0);
}

/*
 * Retrieve the default MTU or min-max MTU range for a given interface.
 *
 *  -- ill_max_frag value tells us the maximum MTU that can be handled by the
 *     datalink. This value is advertised by the driver via DLPI messages
 *     (DL_NOTE_SDU_SIZE/DL_INFO_ACK).
 *
 *  -- ill_current_frag for the most link-types will be same as ill_max_frag
 *     to begin with. However it is dynamically computed for some link-types
 *     like tunnels, based on the tunnel PMTU.
 *
 *  -- ill_mtu is the user set MTU using SIOCSLIFMTU and must lie between
 *     (IPV6_MIN_MTU/IP_MIN_MTU) and ill_max_frag.
 *
 *  -- ill_user_mtu is set by in.ndpd using SIOCSLIFLNKINFO and must lie between
 *     (IPV6_MIN_MTU/IP_MIN_MTU) and ill_max_frag.
 */
int
ip_get_mtu(netstack_t *stack, mod_prop_info_t *pinfo, const char *ifname,
    void *pval, uint_t psize, uint_t flags)
{
	ill_walk_context_t	ctx;
	ill_t			*ill;
	ip_stack_t		*ipst = stack->netstack_ip;
	boolean_t		isv6;
	uint32_t		max_mtu, def_mtu;
	size_t			nbytes = 0;

	if (!(flags & (MOD_PROP_DEFAULT|MOD_PROP_POSSIBLE)))
		return (ENOTSUP);

	if (ifname == NULL || ifname[0] == '\0')
		return (ENOTSUP);

	isv6 = (pinfo->mpi_proto == MOD_PROTO_IPV6 ? B_TRUE : B_FALSE);
	rw_enter(&ipst->ips_ill_g_lock, RW_READER);
	if (isv6)
		ill = ILL_START_WALK_V6(&ctx, ipst);
	else
		ill = ILL_START_WALK_V4(&ctx, ipst);
	for (; ill != NULL; ill = ill_next(&ctx, ill)) {
		if (strcmp(ifname, ill->ill_name) == 0)
			break;
	}
	if (ill == NULL) {
		rw_exit(&ipst->ips_ill_g_lock);
		return (ENXIO);
	}
	max_mtu = ill->ill_max_frag;
	def_mtu = ill->ill_current_frag;
	rw_exit(&ipst->ips_ill_g_lock);

	if (flags & MOD_PROP_DEFAULT) {
		nbytes = snprintf(pval, psize, "%u", def_mtu);
	} else if (flags & MOD_PROP_POSSIBLE) {
		uint32_t	min_mtu;

		min_mtu = isv6 ? IPV6_MIN_MTU : IP_MIN_MTU;
		nbytes = snprintf(pval, psize, "%u-%u", min_mtu, max_mtu);
	} else {
		return (ENOTSUP);
	}

	if (nbytes >= psize)
		return (ENOBUFS);
	return (0);
}

/*
 * See the comments for ip[6]_strict_src_multihoming for an explanation
 * of the semanitcs.
 */
void
ip_set_src_multihoming_common(ulong_t new_value, ulong_t old_value,
    boolean_t isv6, ip_stack_t *ipst)
{
	if (isv6)
		ipst->ips_ipv6_strict_src_multihoming = new_value;
	else
		ipst->ips_ip_strict_src_multihoming = new_value;
	if (new_value != old_value) {
		if (!isv6) {
			if (old_value == 0) {
				ire_walk_v4(ip_ire_rebind_walker, NULL,
				    ALL_ZONES, ipst);
			} else if (new_value == 0) {
				ire_walk_v4(ip_ire_unbind_walker, NULL,
				    ALL_ZONES, ipst);
			}
			ipcl_walk(conn_ire_revalidate, (void *)B_FALSE, ipst);
		} else {
			if (old_value == 0) {
				ire_walk_v6(ip_ire_rebind_walker, NULL,
				    ALL_ZONES, ipst);
			} else if (new_value == 0) {
				ire_walk_v6(ip_ire_unbind_walker, NULL,
				    ALL_ZONES, ipst);
			}
			ipcl_walk(conn_ire_revalidate, (void *)B_TRUE, ipst);
		}
	}
}

/* ARGSUSED */
static int
ip_set_src_multihoming(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
    const char *ifname, const void* pval, uint_t flags)
{
	unsigned long	new_value, old_value;
	boolean_t	isv6;
	ip_stack_t	*ipst = stack->netstack_ip;
	int		err;

	old_value = pinfo->prop_cur_uval;

	if ((err = mod_uint32_value(pval, pinfo, flags, &new_value)) != 0)
		return (err);
	pinfo->prop_cur_uval = new_value;
	isv6 = (strcmp(pinfo->mpi_name, "ip6_strict_src_multihoming") == 0);
	ip_set_src_multihoming_common(new_value, old_value, isv6, ipst);
	return (0);
}


/* ARGSUSED */
static int
ip_set_hostmodel(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
    const char *ifname, const void* pval, uint_t flags)
{
	ip_hostmodel_t	new_value, old_value;
	ip_stack_t	*ipst = stack->netstack_ip;
	uint32_t	old_src_multihoming;
	int		err;
	ulong_t		tmp;
	boolean_t	isv6;

	old_value = pinfo->prop_cur_uval;

	if ((err = mod_uint32_value(pval, pinfo, flags, &tmp)) != 0)
		return (err);
	new_value = tmp;
	pinfo->prop_cur_uval = new_value;

	switch (old_value) {
	case IP_WEAK_ES:
		old_src_multihoming = 0;
		break;
	case IP_SRC_PRI_ES:
		old_src_multihoming = 1;
		break;
	case IP_STRONG_ES:
		old_src_multihoming = 2;
		break;
	default:
		ASSERT(0);
		old_src_multihoming = IP_MAXVAL_ES;
		break;
	}
	/*
	 * Changes to src_multihoming may require ire's to be rebound/unbound,
	 * and also require generation number resets. Changes to dst_multihoming
	 * require a simple reset of the value.
	 */
	isv6 = (pinfo->mpi_proto == MOD_PROTO_IPV6);
	if (new_value != old_value) {
		switch (new_value) {
		case IP_WEAK_ES:
			ip_set_src_multihoming_common(0, old_src_multihoming,
			    isv6, ipst);
			if (isv6)
				ipst->ips_ipv6_strict_dst_multihoming = 0;
			else
				ipst->ips_ip_strict_dst_multihoming = 0;
			break;
		case IP_SRC_PRI_ES:
			ip_set_src_multihoming_common(1, old_src_multihoming,
			    isv6, ipst);
			if (isv6)
				ipst->ips_ipv6_strict_dst_multihoming = 0;
			else
				ipst->ips_ip_strict_dst_multihoming = 0;
			break;
		case IP_STRONG_ES:
			ip_set_src_multihoming_common(2, old_src_multihoming,
			    isv6, ipst);
			if (isv6)
				ipst->ips_ipv6_strict_dst_multihoming = 1;
			else
				ipst->ips_ip_strict_dst_multihoming = 1;
			break;
		default:
			return (EINVAL);
		}
	}
	return (0);
}

/* ARGSUSED */
int
ip_get_hostmodel(netstack_t *stack, mod_prop_info_t *pinfo, const char *ifname,
    void *pval, uint_t psize, uint_t flags)
{
	boolean_t	isv6 = (pinfo->mpi_proto == MOD_PROTO_IPV6);
	ip_stack_t	*ipst = stack->netstack_ip;
	ip_hostmodel_t	hostmodel;

	if (psize < sizeof (hostmodel))
		return (ENOBUFS);
	bzero(pval, psize);
	if (!isv6) {
		if (ipst->ips_ip_strict_src_multihoming == 0 &&
		    ipst->ips_ip_strict_dst_multihoming == 0)
			hostmodel = IP_WEAK_ES;
		else if (ipst->ips_ip_strict_src_multihoming == 1 &&
		    ipst->ips_ip_strict_dst_multihoming == 0)
			hostmodel = IP_SRC_PRI_ES;
		else if (ipst->ips_ip_strict_src_multihoming == 2 &&
		    ipst->ips_ip_strict_dst_multihoming == 1)
			hostmodel = IP_STRONG_ES;
		else
			hostmodel = IP_MAXVAL_ES;
	} else {
		if (ipst->ips_ipv6_strict_src_multihoming == 0 &&
		    ipst->ips_ipv6_strict_dst_multihoming == 0)
			hostmodel = IP_WEAK_ES;
		else if (ipst->ips_ipv6_strict_src_multihoming == 1 &&
		    ipst->ips_ipv6_strict_dst_multihoming == 0)
			hostmodel = IP_SRC_PRI_ES;
		else if (ipst->ips_ipv6_strict_src_multihoming == 2 &&
		    ipst->ips_ipv6_strict_dst_multihoming == 1)
			hostmodel = IP_STRONG_ES;
		else
			hostmodel = IP_MAXVAL_ES;
	}
	bcopy(&hostmodel, pval, sizeof (hostmodel));
	return (0);
}

/*
 * All of these are alterable, within the min/max values given, at run time.
 *
 * Note: All those tunables which do not start with "_" are Committed and
 * therefore are public. See PSARC 2010/080.
 */
mod_prop_info_t ip_propinfo_tbl[] = {
	/* tunable - 0 */
	{ "_respond_to_address_mask_broadcast", MOD_PROTO_IP,
	    mod_set_boolean, mod_get_boolean,
	    {B_FALSE}, {B_FALSE} },

	{ "_respond_to_echo_broadcast", MOD_PROTO_IP,
	    mod_set_boolean, mod_get_boolean,
	    {B_TRUE},  {B_TRUE} },

	{ "_respond_to_echo_multicast", MOD_PROTO_IPV4,
	    mod_set_boolean, mod_get_boolean,
	    {B_TRUE}, {B_TRUE} },

	{ "_respond_to_timestamp", MOD_PROTO_IP,
	    mod_set_boolean, mod_get_boolean,
	    {B_FALSE}, {B_FALSE} },

	{ "_respond_to_timestamp_broadcast", MOD_PROTO_IP,
	    mod_set_boolean, mod_get_boolean,
	    {B_FALSE}, {B_FALSE} },

	{ "_send_redirects", MOD_PROTO_IPV4,
	    mod_set_boolean, mod_get_boolean,
	    {B_TRUE}, {B_TRUE} },

	{ "_forward_directed_broadcasts", MOD_PROTO_IP,
	    mod_set_boolean, mod_get_boolean,
	    {B_FALSE}, {B_FALSE} },

	{ "_mrtdebug", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {0, 10, 0}, {0} },

	{ "_ire_reclaim_fraction", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {1, 8, 3}, {3} },

	{ "_nce_reclaim_fraction", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {1, 8, 3}, {3} },

	/* tunable - 10 */
	{ "_dce_reclaim_fraction", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {1, 8, 3}, {3} },

	{ "ttl", MOD_PROTO_IPV4,
	    mod_set_uint32, mod_get_uint32,
	    {1, 255, 255}, {255} },

	{ "_forward_src_routed", MOD_PROTO_IPV4,
	    mod_set_boolean, mod_get_boolean,
	    {B_FALSE}, {B_FALSE} },

	{ "_wroff_extra", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {0, 256, 32}, {32} },

	/* following tunable is in seconds - a deviant! */
	{ "_pathmtu_interval", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {2, 999999999, 60*20}, {60*20} },

	{ "_icmp_return_data_bytes", MOD_PROTO_IPV4,
	    mod_set_uint32, mod_get_uint32,
	    {8, 65536, 64}, {64} },

	{ "_path_mtu_discovery", MOD_PROTO_IP,
	    mod_set_boolean, mod_get_boolean,
	    {B_TRUE}, {B_TRUE} },

	{ "_pmtu_min", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {68, 65535, 576}, {576} },

	{ "_ignore_redirect", MOD_PROTO_IPV4,
	    mod_set_boolean, mod_get_boolean,
	    {B_FALSE}, {B_FALSE} },

	{ "_arp_icmp_error", MOD_PROTO_IP,
	    mod_set_boolean, mod_get_boolean,
	    {B_FALSE}, {B_FALSE} },

	/* tunable - 20 */
	{ "_broadcast_ttl", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {1, 254, 1}, {1} },

	{ "_icmp_err_interval", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {0, 99999, 100}, {100} },

	{ "_icmp_err_burst", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {1, 99999, 10}, {10} },

	{ "_reass_queue_bytes", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {0, 999999999, 1000000}, {1000000} },

	/*
	 * See comments for ip_strict_src_multihoming for an explanation
	 * of the semantics of ip_strict_dst_multihoming
	 */
	{ "_strict_dst_multihoming", MOD_PROTO_IPV4,
	    mod_set_uint32, mod_get_uint32,
	    {0, 1, 0}, {0} },

	{ "_addrs_per_if", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {1, MAX_ADDRS_PER_IF, 256}, {256} },

	{ "_ipsec_override_persocket_policy", MOD_PROTO_IP,
	    mod_set_boolean, mod_get_boolean,
	    {B_FALSE}, {B_FALSE} },

	{ "_icmp_accept_clear_messages", MOD_PROTO_IP,
	    mod_set_boolean, mod_get_boolean,
	    {B_TRUE}, {B_TRUE} },

	{ "_igmp_accept_clear_messages", MOD_PROTO_IP,
	    mod_set_boolean, mod_get_boolean,
	    {B_TRUE}, {B_TRUE} },

	{ "_ndp_delay_first_probe_time", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {2, 999999999, ND_DELAY_FIRST_PROBE_TIME},
	    {ND_DELAY_FIRST_PROBE_TIME} },

	/* tunable - 30 */
	{ "_ndp_max_unicast_solicit", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {1, 999999999, ND_MAX_UNICAST_SOLICIT}, {ND_MAX_UNICAST_SOLICIT} },

	{ "hoplimit", MOD_PROTO_IPV6,
	    mod_set_uint32, mod_get_uint32,
	    {1, 255, IPV6_MAX_HOPS}, {IPV6_MAX_HOPS} },

	{ "_icmp_return_data_bytes", MOD_PROTO_IPV6,
	    mod_set_uint32, mod_get_uint32,
	    {8, IPV6_MIN_MTU, IPV6_MIN_MTU}, {IPV6_MIN_MTU} },

	{ "_forward_src_routed", MOD_PROTO_IPV6,
	    mod_set_boolean, mod_get_boolean,
	    {B_FALSE}, {B_FALSE} },

	{ "_respond_to_echo_multicast", MOD_PROTO_IPV6,
	    mod_set_boolean, mod_get_boolean,
	    {B_TRUE}, {B_TRUE} },

	{ "_send_redirects", MOD_PROTO_IPV6,
	    mod_set_boolean, mod_get_boolean,
	    {B_TRUE}, {B_TRUE} },

	{ "_ignore_redirect", MOD_PROTO_IPV6,
	    mod_set_boolean, mod_get_boolean,
	    {B_FALSE}, {B_FALSE} },

	/*
	 * See comments for ip6_strict_src_multihoming for an explanation
	 * of the semantics of ip6_strict_dst_multihoming
	 */
	{ "_strict_dst_multihoming", MOD_PROTO_IPV6,
	    mod_set_uint32, mod_get_uint32,
	    {0, 1, 0}, {0} },

	{ "_src_check", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {0, 2, 2}, {2} },

	{ "_ipsec_policy_log_interval", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {0, 999999, 1000}, {1000} },

	/* tunable - 40 */
	{ "_pim_accept_clear_messages", MOD_PROTO_IP,
	    mod_set_boolean, mod_get_boolean,
	    {B_TRUE}, {B_TRUE} },

	{ "_ndp_unsolicit_interval", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {1000, 20000, 2000}, {2000} },

	{ "_ndp_unsolicit_count", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {1, 20, 3}, {3} },

	{ "_ignore_home_address_opt", MOD_PROTO_IPV6,
	    mod_set_boolean, mod_get_boolean,
	    {B_TRUE}, {B_TRUE} },

	{ "_policy_mask", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {0, 15, 0}, {0} },

	{ "_ecmp_behavior", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {0, 2, 2}, {2} },

	{ "_multirt_ttl", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {0, 255, 1}, {1} },

	/* following tunable is in seconds - a deviant */
	{ "_ire_badcnt_lifetime", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {0, 3600, 60}, {60} },

	{ "_max_temp_idle", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {0, 999999, 60*60*24}, {60*60*24} },

	{ "_max_temp_defend", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {0, 1000, 1}, {1} },

	/* tunable - 50 */
	/*
	 * when a conflict of an active address is detected,
	 * defend up to ip_max_defend times, within any
	 * ip_defend_interval span.
	 */
	{ "_max_defend", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {0, 1000, 3}, {3} },

	{ "_defend_interval", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {0, 999999, 30}, {30} },

	{ "_dup_recovery", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {0, 3600000, 300000}, {300000} },

	{ "_restrict_interzone_loopback", MOD_PROTO_IP,
	    mod_set_boolean, mod_get_boolean,
	    {B_TRUE}, {B_TRUE} },

	{ "_lso_outbound", MOD_PROTO_IP,
	    mod_set_boolean, mod_get_boolean,
	    {B_TRUE}, {B_TRUE} },

	{ "_igmp_max_version", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {IGMP_V1_ROUTER, IGMP_V3_ROUTER, IGMP_V3_ROUTER},
	    {IGMP_V3_ROUTER} },

	{ "_mld_max_version", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {MLD_V1_ROUTER, MLD_V2_ROUTER, MLD_V2_ROUTER}, {MLD_V2_ROUTER} },

	{ "forwarding", MOD_PROTO_IPV4,
	    ip_set_forwarding, ip_get_forwarding,
	    {IP_FORWARD_NEVER}, {IP_FORWARD_NEVER} },

	{ "forwarding", MOD_PROTO_IPV6,
	    ip_set_forwarding, ip_get_forwarding,
	    {IP_FORWARD_NEVER}, {IP_FORWARD_NEVER} },

	{ "_reasm_timeout", MOD_PROTO_IPV4,
	    mod_set_uint32, mod_get_uint32,
	    {5, 255, IP_REASM_TIMEOUT},
	    {IP_REASM_TIMEOUT} },

	/* tunable - 60 */
	{ "_reasm_timeout", MOD_PROTO_IPV6,
	    mod_set_uint32, mod_get_uint32,
	    {5, 255, IPV6_REASM_TIMEOUT},
	    {IPV6_REASM_TIMEOUT} },

	{ "_cgtp_filter", MOD_PROTO_IP,
	    ip_set_cgtp_filter, mod_get_boolean,
	    {B_FALSE}, {B_FALSE} },

	/* delay before sending first probe: */
	{ "_arp_probe_delay", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {0, 20000, 1000}, {1000} },

	{ "_arp_fastprobe_delay", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {0, 20000, 100}, {100} },

	/* interval at which DAD probes are sent: */
	{ "_arp_probe_interval", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {10, 20000, 1500}, {1500} },

	{ "_arp_fastprobe_interval", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {10, 20000, 150}, {150} },

	{ "_arp_probe_count", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {0, 20, 3}, {3} },

	{ "_arp_fastprobe_count", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {0, 20, 3}, {3} },

	{ "_dad_announce_interval", MOD_PROTO_IPV4,
	    mod_set_uint32, mod_get_uint32,
	    {0, 3600000, 15000}, {15000} },

	{ "_dad_announce_interval", MOD_PROTO_IPV6,
	    mod_set_uint32, mod_get_uint32,
	    {0, 3600000, 15000}, {15000} },

	/* tunable - 70 */
	/*
	 * Rate limiting parameters for DAD defense used in
	 * ill_defend_rate_limit():
	 * defend_rate : pkts/hour permitted
	 * defend_interval : time that can elapse before we send out a
	 *			DAD defense.
	 * defend_period: denominator for defend_rate (in seconds).
	 */
	{ "_arp_defend_interval", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {0, 3600000, 300000}, {300000} },

	{ "_arp_defend_rate", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {0, 20000, 100}, {100} },

	{ "_ndp_defend_interval", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {0, 3600000, 300000}, {300000} },

	{ "_ndp_defend_rate", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {0, 20000, 100}, {100} },

	{ "_arp_defend_period", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {5, 86400, 3600}, {3600} },

	{ "_ndp_defend_period", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {5, 86400, 3600}, {3600} },

	{ "_icmp_return_pmtu", MOD_PROTO_IPV4,
	    mod_set_boolean, mod_get_boolean,
	    {B_TRUE}, {B_TRUE} },

	{ "_icmp_return_pmtu", MOD_PROTO_IPV6,
	    mod_set_boolean, mod_get_boolean,
	    {B_TRUE}, {B_TRUE} },

	/*
	 * publish count/interval values used to announce local addresses
	 * for IPv4, IPv6.
	 */
	{ "_arp_publish_count", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {1, 20, 5}, {5} },

	{ "_arp_publish_interval", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {1000, 20000, 2000}, {2000} },

	/* tunable - 80 */
	/*
	 * The ip*strict_src_multihoming and ip*strict_dst_multihoming provide
	 * a range of choices for setting strong/weak/preferred end-system
	 * behavior. The semantics for setting these are:
	 *
	 * ip*_strict_dst_multihoming = 0
	 *    weak end system model for managing ip destination addresses.
	 *    A packet with IP dst D1 that's received on interface I1 will be
	 *    accepted as long as D1 is one of the local addresses on
	 *    the machine, even if D1 is not configured on I1.
	 * ip*strict_dst_multihioming = 1
	 *    strong end system model for managing ip destination addresses.
	 *    A packet with IP dst D1 that's received on interface I1 will be
	 *    accepted if, and only if, D1 is configured on I1.
	 *
	 * ip*strict_src_multihoming = 0
	 *    Source agnostic route selection for outgoing packets: the
	 *    outgoing interface for a packet will be computed using
	 *    default algorithms for route selection, where the route
	 *    with the longest matching prefix is chosen for the output
	 *    unless other route selection constraints are explicitly
	 *    specified during routing table lookup.  This may result
	 *    in packet being sent out on interface I2 with source
	 *    address S1, even though S1 is not a configured address on I2.
	 * ip*strict_src_multihoming = 1
	 *    Preferred source aware route selection for outgoing packets: for
	 *    a packet with source S2, destination D2, the route selection
	 *    algorithm will first attempt to find a route for the destination
	 *    that goes out through an interface where S2 is
	 *    configured. If such a route cannot be found, then the
	 *    best-matching route for D2 will be selected.
	 * ip*strict_src_multihoming = 2
	 *    Source aware route selection for outgoing packets: a packet will
	 *    be sent out on an interface I2 only if the src address S2 of the
	 *    packet is a configured address on I2. In conjunction with
	 *    the setting 'ip_strict_dst_multihoming == 1', this will result in
	 *    the implementation of Strong ES as defined in Section 3.3.4.2 of
	 *    RFC 1122
	 */
	{ "_strict_src_multihoming", MOD_PROTO_IPV4,
	    ip_set_src_multihoming, mod_get_uint32,
	    {0, 2, 0}, {0} },

	{ "_strict_src_multihoming", MOD_PROTO_IPV6,
	    ip_set_src_multihoming, mod_get_uint32,
	    {0, 2, 0}, {0} },

#ifdef DEBUG
	{ "_drop_inbound_icmpv6", MOD_PROTO_IPV6,
	    mod_set_boolean, mod_get_boolean,
	    {B_FALSE}, {B_FALSE} },
#else
	{ "", 0, NULL, NULL, {0}, {0} },
#endif

	{ "_dce_reclaim_threshold", MOD_PROTO_IP,
	    mod_set_uint32, mod_get_uint32,
	    {1, 100000, 32}, {32} },

	{ "mtu", MOD_PROTO_IPV4, NULL, ip_get_mtu, {0}, {0} },

	{ "mtu", MOD_PROTO_IPV6, NULL, ip_get_mtu, {0}, {0} },

	/*
	 * The following entry is a placeholder for `ip_debug' global
	 * variable. Within these callback functions, we will be
	 * setting/getting the global variable
	 */
	{ "_debug", MOD_PROTO_IP,
	    ip_set_debug, ip_get_debug,
	    {0, 20, 0}, {0} },

	{ "hostmodel", MOD_PROTO_IPV4, ip_set_hostmodel, ip_get_hostmodel,
	    {IP_WEAK_ES, IP_STRONG_ES, IP_WEAK_ES}, {IP_WEAK_ES} },

	{ "hostmodel", MOD_PROTO_IPV6, ip_set_hostmodel, ip_get_hostmodel,
	    {IP_WEAK_ES, IP_STRONG_ES, IP_WEAK_ES}, {IP_WEAK_ES} },

	{ "?", MOD_PROTO_IP, NULL, mod_get_allprop, {0}, {0} },

	{ NULL, 0, NULL, NULL, {0}, {0} }
};

int ip_propinfo_count = A_CNT(ip_propinfo_tbl);