Print this page
3942 inject sanity into ipadm tcp buffer size properties
3943 _snd_lowat_fraction tcp tunable has no effect
Reviewed by: Adam Leventhal <ahl@delphix.com>
Reviewed by: Peng Dai <peng.dai@delphix.com>

@@ -19,10 +19,11 @@
  * CDDL HEADER END
  */
 /*
  * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 1990 Mentat Inc.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
  */
 
 #include <inet/tunables.h>
 #include <sys/md5.h>
 #include <inet/common.h>

@@ -36,10 +37,28 @@
 #include <inet/udp_impl.h>
 #include <inet/sctp/sctp_stack.h>
 #include <inet/sctp/sctp_impl.h>
 #include <inet/tunables.h>
 
+mod_prop_info_t *
+mod_prop_lookup(mod_prop_info_t ptbl[], const char *prop_name, uint_t proto)
+{
+        mod_prop_info_t *pinfo;
+
+        /*
+         * Walk the ptbl array looking for a property that has the requested
+         * name and protocol number.  Note that we assume that all protocol
+         * tables are terminated by an entry with a NULL property name.
+         */
+        for (pinfo = ptbl; pinfo->mpi_name != NULL; pinfo++) {
+                if (strcmp(pinfo->mpi_name, prop_name) == 0 &&
+                    pinfo->mpi_proto == proto)
+                        return (pinfo);
+        }
+        return (NULL);
+}
+
 static int
 prop_perm2const(mod_prop_info_t *pinfo)
 {
         if (pinfo->mpi_setf == NULL)
                 return (MOD_PROP_PERM_READ);

@@ -52,11 +71,11 @@
  * Modifies the value of the property to default value or to the `pval'
  * specified by the user.
  */
 /* ARGSUSED */
 int
-mod_set_boolean(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
+mod_set_boolean(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;
 

@@ -77,11 +96,11 @@
  * Retrieves property permission, default value, current value or possible
  * values for those properties whose value type is boolean_t.
  */
 /* ARGSUSED */
 int
-mod_get_boolean(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
+mod_get_boolean(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);

@@ -126,11 +145,11 @@
  * Modifies the value of the property to default value or to the `pval'
  * specified by the user.
  */
 /* ARGSUSED */
 int
-mod_set_uint32(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
+mod_set_uint32(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;
 

@@ -143,16 +162,16 @@
 /*
  * Rounds up the value to make it multiple of 8.
  */
 /* ARGSUSED */
 int
-mod_set_aligned(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
+mod_set_aligned(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
     const char *ifname, const void* pval, uint_t flags)
 {
         int     err;
 
-        if ((err = mod_set_uint32(cbarg, cr, pinfo, ifname, pval, flags)) != 0)
+        if ((err = mod_set_uint32(stack, cr, pinfo, ifname, pval, flags)) != 0)
                 return (err);
 
         /* if required, align the value to multiple of 8 */
         if (pinfo->prop_cur_uval & 0x7) {
                 pinfo->prop_cur_uval &= ~0x7;

@@ -166,11 +185,11 @@
  * Retrieves property permission, default value, current value or possible
  * values for those properties whose value type is uint32_t.
  */
 /* ARGSUSED */
 int
-mod_get_uint32(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
+mod_get_uint32(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);

@@ -190,25 +209,90 @@
                 return (ENOBUFS);
         return (0);
 }
 
 /*
+ * The range of the buffer size properties has a static lower bound configured
+ * in the property info structure of the property itself, and a dynamic upper
+ * bound.  The upper bound is the current value of the "max_buf" property
+ * in the appropriate protocol property table.
+ */
+static void
+mod_get_buf_prop_range(mod_prop_info_t ptbl[], mod_prop_info_t *pinfo,
+    uint32_t *min, uint32_t *max)
+{
+        mod_prop_info_t *maxbuf_pinfo = mod_prop_lookup(ptbl, "max_buf",
+            pinfo->mpi_proto);
+
+        *min = pinfo->prop_min_uval;
+        *max = maxbuf_pinfo->prop_cur_uval;
+}
+
+/*
+ * Modifies the value of the buffer size property to its default value or to
+ * the value specified by the user.  This is similar to mod_set_uint32() except
+ * that the value has a dynamically bounded range (see mod_get_buf_prop_range()
+ * for details).
+ */
+/* ARGSUSED */
+int
+mod_set_buf_prop(mod_prop_info_t ptbl[], netstack_t *stack, cred_t *cr,
+    mod_prop_info_t *pinfo, const char *ifname, const void *pval, uint_t flags)
+{
+        unsigned long   new_value;
+        char            *end;
+        uint32_t        min, max;
+
+        if (flags & MOD_PROP_DEFAULT) {
+                pinfo->prop_cur_uval = pinfo->prop_def_uval;
+                return (0);
+        }
+
+        if (ddi_strtoul(pval, &end, 10, &new_value) != 0 || *end != '\0')
+                return (EINVAL);
+
+        mod_get_buf_prop_range(ptbl, pinfo, &min, &max);
+        if (new_value < min || new_value > max)
+                return (ERANGE);
+
+        pinfo->prop_cur_uval = new_value;
+        return (0);
+}
+
+/*
+ * Retrieves property permissions, default value, current value, or possible
+ * values for buffer size properties.  While these properties have integer
+ * values, they have a dynamic range (see mod_get_buf_prop_range() for
+ * details).  As such, they need to be handled differently.
+ */
+int
+mod_get_buf_prop(mod_prop_info_t ptbl[], netstack_t *stack,
+    mod_prop_info_t *pinfo, const char *ifname, void *pval, uint_t psize,
+    uint_t flags)
+{
+        size_t nbytes;
+        uint32_t min, max;
+
+        if (flags & MOD_PROP_POSSIBLE) {
+                mod_get_buf_prop_range(ptbl, pinfo, &min, &max);
+                nbytes = snprintf(pval, psize, "%u-%u", min, max);
+                return (nbytes < psize ? 0 : ENOBUFS);
+        }
+        return (mod_get_uint32(stack, pinfo, ifname, pval, psize, flags));
+}
+
+/*
  * Implements /sbin/ndd -get /dev/ip ?, for all the modules. Needed for
  * backward compatibility with /sbin/ndd.
  */
 /* ARGSUSED */
 int
-mod_get_allprop(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
+mod_get_allprop(netstack_t *stack, mod_prop_info_t *pinfo, const char *ifname,
     void *val, uint_t psize, uint_t flags)
 {
         char            *pval = val;
         mod_prop_info_t *ptbl, *prop;
-        ip_stack_t      *ipst;
-        tcp_stack_t     *tcps;
-        sctp_stack_t    *sctps;
-        udp_stack_t     *us;
-        icmp_stack_t    *is;
         uint_t          size;
         size_t          nbytes = 0, tbytes = 0;
 
         bzero(pval, psize);
         size = psize;

@@ -215,28 +299,23 @@
 
         switch (pinfo->mpi_proto) {
         case MOD_PROTO_IP:
         case MOD_PROTO_IPV4:
         case MOD_PROTO_IPV6:
-                ipst = (ip_stack_t *)cbarg;
-                ptbl = ipst->ips_propinfo_tbl;
+                ptbl = stack->netstack_ip->ips_propinfo_tbl;
                 break;
         case MOD_PROTO_RAWIP:
-                is = (icmp_stack_t *)cbarg;
-                ptbl = is->is_propinfo_tbl;
+                ptbl = stack->netstack_icmp->is_propinfo_tbl;
                 break;
         case MOD_PROTO_TCP:
-                tcps = (tcp_stack_t *)cbarg;
-                ptbl = tcps->tcps_propinfo_tbl;
+                ptbl = stack->netstack_tcp->tcps_propinfo_tbl;
                 break;
         case MOD_PROTO_UDP:
-                us = (udp_stack_t *)cbarg;
-                ptbl = us->us_propinfo_tbl;
+                ptbl = stack->netstack_udp->us_propinfo_tbl;
                 break;
         case MOD_PROTO_SCTP:
-                sctps = (sctp_stack_t *)cbarg;
-                ptbl = sctps->sctps_propinfo_tbl;
+                ptbl = stack->netstack_sctp->sctps_propinfo_tbl;
                 break;
         default:
                 return (EINVAL);
         }
 

@@ -262,11 +341,11 @@
  * Hold a lock while changing *_epriv_ports to prevent multiple
  * threads from changing it at the same time.
  */
 /* ARGSUSED */
 int
-mod_set_extra_privports(void *cbarg, cred_t *cr, mod_prop_info_t *pinfo,
+mod_set_extra_privports(netstack_t *stack, cred_t *cr, mod_prop_info_t *pinfo,
     const char *ifname, const void* val, uint_t flags)
 {
         uint_t          proto = pinfo->mpi_proto;
         tcp_stack_t     *tcps;
         sctp_stack_t    *sctps;

@@ -291,23 +370,23 @@
                 }
         }
 
         switch (proto) {
         case MOD_PROTO_TCP:
-                tcps = (tcp_stack_t *)cbarg;
+                tcps = stack->netstack_tcp;
                 lock = &tcps->tcps_epriv_port_lock;
                 ports = tcps->tcps_g_epriv_ports;
                 nports = tcps->tcps_g_num_epriv_ports;
                 break;
         case MOD_PROTO_UDP:
-                us = (udp_stack_t *)cbarg;
+                us = stack->netstack_udp;
                 lock = &us->us_epriv_port_lock;
                 ports = us->us_epriv_ports;
                 nports = us->us_num_epriv_ports;
                 break;
         case MOD_PROTO_SCTP:
-                sctps = (sctp_stack_t *)cbarg;
+                sctps = stack->netstack_sctp;
                 lock = &sctps->sctps_epriv_port_lock;
                 ports = sctps->sctps_g_epriv_ports;
                 nports = sctps->sctps_g_num_epriv_ports;
                 break;
         default:

@@ -380,12 +459,12 @@
  * - the fact that the address of the array and its size never changes
  * - the atomic assignment of the elements of the array
  */
 /* ARGSUSED */
 int
-mod_get_extra_privports(void *cbarg, mod_prop_info_t *pinfo, const char *ifname,
-    void *val, uint_t psize, uint_t flags)
+mod_get_extra_privports(netstack_t *stack, mod_prop_info_t *pinfo,
+    const char *ifname, void *val, uint_t psize, uint_t flags)
 {
         uint_t          proto = pinfo->mpi_proto;
         tcp_stack_t     *tcps;
         sctp_stack_t    *sctps;
         udp_stack_t     *us;

@@ -409,21 +488,21 @@
                 goto ret;
         }
 
         switch (proto) {
         case MOD_PROTO_TCP:
-                tcps = (tcp_stack_t *)cbarg;
+                tcps = stack->netstack_tcp;
                 ports = tcps->tcps_g_epriv_ports;
                 nports = tcps->tcps_g_num_epriv_ports;
                 break;
         case MOD_PROTO_UDP:
-                us = (udp_stack_t *)cbarg;
+                us = stack->netstack_udp;
                 ports = us->us_epriv_ports;
                 nports = us->us_num_epriv_ports;
                 break;
         case MOD_PROTO_SCTP:
-                sctps = (sctp_stack_t *)cbarg;
+                sctps = stack->netstack_sctp;
                 ports = sctps->sctps_g_epriv_ports;
                 nports = sctps->sctps_g_num_epriv_ports;
                 break;
         default:
                 return (ENOTSUP);