Author: hrs
Date: Wed Oct  1 21:37:32 2014
New Revision: 272386
URL: https://svnweb.freebsd.org/changeset/base/272386

Log:
  Virtualize lagg(4) cloner.  This change fixes a panic when tearing down
  if_lagg(4) interfaces which were cloned in a vnet jail.
  
  Sysctl nodes which are dynamically generated for each cloned interface
  (net.link.lagg.N.*) have been removed, and use_flowid and flowid_shift
  ifconfig(8) parameters have been added instead.  Flags and per-interface
  statistics counters are displayed in "ifconfig -v".
  
  CR:   D842

Modified:
  head/sbin/ifconfig/ifconfig.8
  head/sbin/ifconfig/iflagg.c
  head/share/man/man4/lagg.4
  head/sys/net/ieee8023ad_lacp.c
  head/sys/net/if_lagg.c
  head/sys/net/if_lagg.h

Modified: head/sbin/ifconfig/ifconfig.8
==============================================================================
--- head/sbin/ifconfig/ifconfig.8       Wed Oct  1 21:24:58 2014        
(r272385)
+++ head/sbin/ifconfig/ifconfig.8       Wed Oct  1 21:37:32 2014        
(r272386)
@@ -28,7 +28,7 @@
 .\"     From: @(#)ifconfig.8   8.3 (Berkeley) 1/5/94
 .\" $FreeBSD$
 .\"
-.Dd September 9, 2014
+.Dd October 1, 2014
 .Dt IFCONFIG 8
 .Os
 .Sh NAME
@@ -679,7 +679,7 @@ Set a flag to enable Neighbor Unreachabi
 Clear a flag
 .Cm nud .
 .It Cm no_prefer_iface
-Set a flag to not honor rule 5 of source address selection in RFC 3484.        
 
+Set a flag to not honor rule 5 of source address selection in RFC 3484.
 In practice this means the address on the outgoing interface will not be
 preferred, effectively yielding the decision to the address selection
 policy table, configurable with
@@ -2331,9 +2331,16 @@ Remove the interface named by
 from the aggregation interface.
 .It Cm laggproto Ar proto
 Set the aggregation protocol.
-The default is failover.
-The available options are failover, lacp, loadbalance, roundrobin, broadcast
-and none.
+The default is
+.Li failover .
+The available options are
+.Li failover ,
+.Li lacp ,
+.Li loadbalance ,
+.Li roundrobin ,
+.Li broadcast
+and
+.Li none .
 .It Cm lagghash Ar option Ns Oo , Ns Ar option Oc
 Set the packet layers to hash for aggregation protocols which load balance.
 The default is
@@ -2348,6 +2355,34 @@ src/dst address for IPv4 or IPv6.
 .It Cm l4
 src/dst port for TCP/UDP/SCTP.
 .El
+.It Cm use_flowid
+Enable local hash computation for RSS hash on the interface.
+The
+.Li loadbalance
+and
+.Li lacp
+modes will use the RSS hash from the network card if available
+to avoid computing one, this may give poor traffic distribution
+if the hash is invalid or uses less of the protocol header information.
+.Cm use_flowid
+disables use of RSS hash from the network card.
+The default value can be set via the
+.Va net.link.lagg.default_use_flowid
+.Xr sysctl 8
+variable.
+.Li 0
+means
+.Dq disabled
+and
+.Li 1
+means
+.Dq enabled .
+.It Cm -use_flowid
+Disable local hash computation for RSS hash on the interface.
+.It Cm flowid_shift Ar number
+Set a shift parameter for RSS local hash computation.
+Hash is calculated by using flowid bits in a packet header mbuf
+which are shifted by the number of this parameter.
 .El
 .Pp
 The following parameters are specific to IP tunnel interfaces,

Modified: head/sbin/ifconfig/iflagg.c
==============================================================================
--- head/sbin/ifconfig/iflagg.c Wed Oct  1 21:24:58 2014        (r272385)
+++ head/sbin/ifconfig/iflagg.c Wed Oct  1 21:37:32 2014        (r272386)
@@ -68,7 +68,7 @@ setlaggproto(const char *val, int d, int
        bzero(&ra, sizeof(ra));
        ra.ra_proto = LAGG_PROTO_MAX;
 
-       for (i = 0; i < (sizeof(lpr) / sizeof(lpr[0])); i++) {
+       for (i = 0; i < nitems(lpr); i++) {
                if (strcmp(val, lpr[i].lpr_name) == 0) {
                        ra.ra_proto = lpr[i].lpr_proto;
                        break;
@@ -83,6 +83,48 @@ setlaggproto(const char *val, int d, int
 }
 
 static void
+setlaggflowidshift(const char *val, int d, int s, const struct afswtch *afp)
+{
+       struct lagg_reqall ra;
+
+       bzero(&ra, sizeof(ra));
+       ra.ra_opts = LAGG_OPT_FLOWIDSHIFT;
+       strlcpy(ra.ra_ifname, name, sizeof(ra.ra_ifname));
+       ra.ra_flowid_shift = (int)strtol(val, NULL, 10);
+       if (ra.ra_flowid_shift & ~LAGG_OPT_FLOWIDSHIFT_MASK)
+               errx(1, "Invalid flowid_shift option: %s", val);
+       
+       if (ioctl(s, SIOCSLAGG, &ra) != 0)
+               err(1, "SIOCSLAGG");
+}
+
+static void
+setlaggsetopt(const char *val, int d, int s, const struct afswtch *afp)
+{
+       struct lagg_reqall ra;
+
+       bzero(&ra, sizeof(ra));
+       ra.ra_opts = d;
+       switch (ra.ra_opts) {
+       case LAGG_OPT_USE_FLOWID:
+       case -LAGG_OPT_USE_FLOWID:
+       case LAGG_OPT_LACP_STRICT:
+       case -LAGG_OPT_LACP_STRICT:
+       case LAGG_OPT_LACP_TXTEST:
+       case -LAGG_OPT_LACP_TXTEST:
+       case LAGG_OPT_LACP_RXTEST:
+       case -LAGG_OPT_LACP_RXTEST:
+               break;
+       default:
+               err(1, "Invalid lagg option");
+       }
+       strlcpy(ra.ra_ifname, name, sizeof(ra.ra_ifname));
+       
+       if (ioctl(s, SIOCSLAGG, &ra) != 0)
+               err(1, "SIOCSLAGG");
+}
+
+static void
 setlagghash(const char *val, int d, int s, const struct afswtch *afp)
 {
        struct lagg_reqflags rf;
@@ -169,7 +211,7 @@ lagg_status(int s)
        if (ioctl(s, SIOCGLAGG, &ra) == 0) {
                lp = (struct lacp_opreq *)&ra.ra_lacpreq;
 
-               for (i = 0; i < (sizeof(lpr) / sizeof(lpr[0])); i++) {
+               for (i = 0; i < nitems(lpr); i++) {
                        if (ra.ra_proto == lpr[i].lpr_proto) {
                                proto = lpr[i].lpr_name;
                                break;
@@ -197,9 +239,28 @@ lagg_status(int s)
                if (isport)
                        printf(" laggdev %s", rp.rp_ifname);
                putchar('\n');
-               if (verbose && ra.ra_proto == LAGG_PROTO_LACP)
-                       printf("\tlag id: %s\n",
-                           lacp_format_peer(lp, "\n\t\t "));
+               if (verbose) {
+                       printf("\tlagg options:\n");
+                       printf("\t\tuse_flowid: %d\n",
+                           (ra.ra_opts & LAGG_OPT_USE_FLOWID) ? 1 : 0);
+                       printf("\t\tflowid_shift: %d\n", ra.ra_flowid_shift);
+                       switch (ra.ra_proto) {
+                       case LAGG_PROTO_LACP:
+                               printf("\t\tlacp_strict: %d\n",
+                                  (ra.ra_opts & LAGG_OPT_LACP_STRICT) ? 1 : 0);
+                               printf("\t\tlacp_rxtest: %d\n",
+                                  (ra.ra_opts & LAGG_OPT_LACP_RXTEST) ? 1 : 0);
+                               printf("\t\tlacp_txtest: %d\n",
+                                  (ra.ra_opts & LAGG_OPT_LACP_TXTEST) ? 1 : 0);
+                       }
+                       printf("\tlagg statistics:\n");
+                       printf("\t\tactive ports: %d\n", ra.ra_active);
+                       printf("\t\tflapping: %u\n", ra.ra_flapping);
+                       if (ra.ra_proto == LAGG_PROTO_LACP) {
+                               printf("\tlag id: %s\n",
+                                   lacp_format_peer(lp, "\n\t\t "));
+                       }
+               }
 
                for (i = 0; i < ra.ra_ports; i++) {
                        lp = (struct lacp_opreq *)&rpbuf[i].rp_lacpreq;
@@ -226,6 +287,15 @@ static struct cmd lagg_cmds[] = {
        DEF_CMD_ARG("-laggport",        unsetlaggport),
        DEF_CMD_ARG("laggproto",        setlaggproto),
        DEF_CMD_ARG("lagghash",         setlagghash),
+       DEF_CMD("use_flowid",   LAGG_OPT_USE_FLOWID,    setlaggsetopt),
+       DEF_CMD("-use_flowid",  -LAGG_OPT_USE_FLOWID,   setlaggsetopt),
+       DEF_CMD("lacp_strict",  LAGG_OPT_LACP_STRICT,   setlaggsetopt),
+       DEF_CMD("-lacp_strict", -LAGG_OPT_LACP_STRICT,  setlaggsetopt),
+       DEF_CMD("lacp_txtest",  LAGG_OPT_LACP_TXTEST,   setlaggsetopt),
+       DEF_CMD("-lacp_txtest", -LAGG_OPT_LACP_TXTEST,  setlaggsetopt),
+       DEF_CMD("lacp_rxtest",  LAGG_OPT_LACP_RXTEST,   setlaggsetopt),
+       DEF_CMD("-lacp_rxtest", -LAGG_OPT_LACP_RXTEST,  setlaggsetopt),
+       DEF_CMD_ARG("flowid_shift",     setlaggflowidshift),
 };
 static struct afswtch af_lagg = {
        .af_name        = "af_lagg",

Modified: head/share/man/man4/lagg.4
==============================================================================
--- head/share/man/man4/lagg.4  Wed Oct  1 21:24:58 2014        (r272385)
+++ head/share/man/man4/lagg.4  Wed Oct  1 21:37:32 2014        (r272386)
@@ -16,7 +16,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd February 23, 2012
+.Dd October 1, 2014
 .Dt LAGG 4
 .Os
 .Sh NAME
@@ -143,9 +143,9 @@ modes will use the RSS hash from the net
 computing one, this may give poor traffic distribution if the hash is invalid
 or uses less of the protocol header information.
 Local hash computation can be forced per interface by setting the
-.Va net.link.lagg.X.use_flowid
-.Xr sysctl 8
-variable to zero where X is the interface number.
+.Cm use_flowid
+.Xr ifconfig 8
+flag.
 The default for new interfaces is set via the
 .Va net.link.lagg.default_use_flowid
 .Xr sysctl 8 .

Modified: head/sys/net/ieee8023ad_lacp.c
==============================================================================
--- head/sys/net/ieee8023ad_lacp.c      Wed Oct  1 21:24:58 2014        
(r272385)
+++ head/sys/net/ieee8023ad_lacp.c      Wed Oct  1 21:37:32 2014        
(r272386)
@@ -190,14 +190,15 @@ static const char *lacp_format_portid(co
 static void    lacp_dprintf(const struct lacp_port *, const char *, ...)
                    __attribute__((__format__(__printf__, 2, 3)));
 
-static int lacp_debug = 0;
+static VNET_DEFINE(int, lacp_debug);
+#define        V_lacp_debug    VNET(lacp_debug)
 SYSCTL_NODE(_net_link_lagg, OID_AUTO, lacp, CTLFLAG_RD, 0, "ieee802.3ad");
-SYSCTL_INT(_net_link_lagg_lacp, OID_AUTO, debug, CTLFLAG_RWTUN,
-    &lacp_debug, 0, "Enable LACP debug logging (1=debug, 2=trace)");
+SYSCTL_INT(_net_link_lagg_lacp, OID_AUTO, debug, CTLFLAG_RWTUN | CTLFLAG_VNET,
+    &VNET_NAME(lacp_debug), 0, "Enable LACP debug logging (1=debug, 2=trace)");
 
-#define LACP_DPRINTF(a) if (lacp_debug & 0x01) { lacp_dprintf a ; }
-#define LACP_TRACE(a) if (lacp_debug & 0x02) { 
lacp_dprintf(a,"%s\n",__func__); }
-#define LACP_TPRINTF(a) if (lacp_debug & 0x04) { lacp_dprintf a ; }
+#define LACP_DPRINTF(a) if (V_lacp_debug & 0x01) { lacp_dprintf a ; }
+#define LACP_TRACE(a) if (V_lacp_debug & 0x02) { 
lacp_dprintf(a,"%s\n",__func__); }
+#define LACP_TPRINTF(a) if (V_lacp_debug & 0x04) { lacp_dprintf a ; }
 
 /*
  * partner administration variables.
@@ -300,7 +301,7 @@ lacp_pdu_input(struct lacp_port *lp, str
                goto bad;
        }
 
-       if (lacp_debug > 0) {
+        if (V_lacp_debug > 0) {
                lacp_dprintf(lp, "lacpdu receive\n");
                lacp_dump_lacpdu(du);
        }
@@ -385,7 +386,7 @@ lacp_xmit_lacpdu(struct lacp_port *lp)
            sizeof(du->ldu_collector));
        du->ldu_collector.lci_maxdelay = 0;
 
-       if (lacp_debug > 0) {
+       if (V_lacp_debug > 0) {
                lacp_dprintf(lp, "lacpdu transmit\n");
                lacp_dump_lacpdu(du);
        }
@@ -497,12 +498,14 @@ lacp_tick(void *arg)
                if ((lp->lp_state & LACP_STATE_AGGREGATION) == 0)
                        continue;
 
+               CURVNET_SET(lp->lp_ifp->if_vnet);
                lacp_run_timers(lp);
 
                lacp_select(lp);
                lacp_sm_mux(lp);
                lacp_sm_tx(lp);
                lacp_sm_ptx_tx_schedule(lp);
+               CURVNET_RESTORE();
        }
        callout_reset(&lsc->lsc_callout, hz, lacp_tick, lsc);
 }
@@ -747,48 +750,10 @@ lacp_transit_expire(void *vp)
        lsc->lsc_suppress_distributing = FALSE;
 }
 
-static void
-lacp_attach_sysctl(struct lacp_softc *lsc, struct sysctl_oid *p_oid)
-{
-       struct lagg_softc *sc = lsc->lsc_softc;
-
-       SYSCTL_ADD_UINT(&sc->ctx, SYSCTL_CHILDREN(p_oid), OID_AUTO,
-           "lacp_strict_mode",
-           CTLFLAG_RW,
-           &lsc->lsc_strict_mode,
-           lsc->lsc_strict_mode,
-           "Enable LACP strict mode");
-}
-
-static void
-lacp_attach_sysctl_debug(struct lacp_softc *lsc, struct sysctl_oid *p_oid)
-{
-       struct lagg_softc *sc = lsc->lsc_softc;
-       struct sysctl_oid *oid;
-
-       /* Create a child of the parent lagg interface */
-       oid = SYSCTL_ADD_NODE(&sc->ctx, SYSCTL_CHILDREN(p_oid),
-           OID_AUTO, "debug", CTLFLAG_RD, NULL, "DEBUG");
-
-       SYSCTL_ADD_UINT(&sc->ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
-           "rx_test",
-           CTLFLAG_RW,
-           &lsc->lsc_debug.lsc_rx_test,
-           lsc->lsc_debug.lsc_rx_test,
-           "Bitmap of if_dunit entries to drop RX frames for");
-       SYSCTL_ADD_UINT(&sc->ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
-           "tx_test",
-           CTLFLAG_RW,
-           &lsc->lsc_debug.lsc_tx_test,
-           lsc->lsc_debug.lsc_tx_test,
-           "Bitmap of if_dunit entries to drop TX frames for");
-}
-
 void
 lacp_attach(struct lagg_softc *sc)
 {
        struct lacp_softc *lsc;
-       struct sysctl_oid *oid;
 
        lsc = malloc(sizeof(struct lacp_softc), M_DEVBUF, M_WAITOK | M_ZERO);
 
@@ -802,14 +767,6 @@ lacp_attach(struct lagg_softc *sc)
        TAILQ_INIT(&lsc->lsc_aggregators);
        LIST_INIT(&lsc->lsc_ports);
 
-       /* Create a child of the parent lagg interface */
-       oid = SYSCTL_ADD_NODE(&sc->ctx, SYSCTL_CHILDREN(sc->sc_oid),
-           OID_AUTO, "lacp", CTLFLAG_RD, NULL, "LACP");
-
-       /* Attach sysctl nodes */
-       lacp_attach_sysctl(lsc, oid);
-       lacp_attach_sysctl_debug(lsc, oid);
-
        callout_init_mtx(&lsc->lsc_transit_callout, &lsc->lsc_mtx, 0);
        callout_init_mtx(&lsc->lsc_callout, &lsc->lsc_mtx, 0);
 
@@ -875,7 +832,7 @@ lacp_select_tx_port(struct lagg_softc *s
                return (NULL);
        }
 
-       if (sc->use_flowid && (m->m_flags & M_FLOWID))
+       if ((sc->sc_opts & LAGG_OPT_USE_FLOWID) && (m->m_flags & M_FLOWID))
                hash = m->m_pkthdr.flowid >> sc->flowid_shift;
        else
                hash = lagg_hashmbuf(sc, m, lsc->lsc_hashkey);
@@ -1374,7 +1331,7 @@ lacp_sm_mux(struct lacp_port *lp)
        enum lacp_selected selected = lp->lp_selected;
        struct lacp_aggregator *la;
 
-       if (lacp_debug > 1)
+       if (V_lacp_debug > 1)
                lacp_dprintf(lp, "%s: state= 0x%x, selected= 0x%x, "
                    "p_sync= 0x%x, p_collecting= 0x%x\n", __func__,
                    lp->lp_mux_state, selected, p_sync, p_collecting);

Modified: head/sys/net/if_lagg.c
==============================================================================
--- head/sys/net/if_lagg.c      Wed Oct  1 21:24:58 2014        (r272385)
+++ head/sys/net/if_lagg.c      Wed Oct  1 21:37:32 2014        (r272386)
@@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$");
 #include <net/if_types.h>
 #include <net/if_var.h>
 #include <net/bpf.h>
+#include <net/vnet.h>
 
 #if defined(INET) || defined(INET6)
 #include <netinet/in.h>
@@ -81,13 +82,21 @@ static struct {
        {0, NULL}
 };
 
-SLIST_HEAD(__trhead, lagg_softc) lagg_list;    /* list of laggs */
-static struct mtx      lagg_list_mtx;
+VNET_DEFINE(SLIST_HEAD(__trhead, lagg_softc), lagg_list); /* list of laggs */
+#define        V_lagg_list     VNET(lagg_list)
+static VNET_DEFINE(struct mtx, lagg_list_mtx);
+#define        V_lagg_list_mtx VNET(lagg_list_mtx)
+#define        LAGG_LIST_LOCK_INIT(x)          mtx_init(&V_lagg_list_mtx, \
+                                       "if_lagg list", NULL, MTX_DEF)
+#define        LAGG_LIST_LOCK_DESTROY(x)       mtx_destroy(&V_lagg_list_mtx)
+#define        LAGG_LIST_LOCK(x)               mtx_lock(&V_lagg_list_mtx)
+#define        LAGG_LIST_UNLOCK(x)             mtx_unlock(&V_lagg_list_mtx)
 eventhandler_tag       lagg_detach_cookie = NULL;
 
 static int     lagg_clone_create(struct if_clone *, int, caddr_t);
 static void    lagg_clone_destroy(struct ifnet *);
-static struct if_clone *lagg_cloner;
+static VNET_DEFINE(struct if_clone *, lagg_cloner);
+#define        V_lagg_cloner   VNET(lagg_cloner)
 static const char laggname[] = "lagg";
 
 static void    lagg_lladdr(struct lagg_softc *, uint8_t *);
@@ -123,7 +132,6 @@ static void lagg_media_status(struct ifn
 static struct lagg_port *lagg_link_active(struct lagg_softc *,
            struct lagg_port *);
 static const void *lagg_gethdr(struct mbuf *, u_int, u_int, void *);
-static int     lagg_sysctl_active(SYSCTL_HANDLER_ARGS);
 
 /* Simple round robin */
 static void    lagg_rr_attach(struct lagg_softc *);
@@ -232,29 +240,55 @@ SYSCTL_DECL(_net_link);
 SYSCTL_NODE(_net_link, OID_AUTO, lagg, CTLFLAG_RW, 0,
     "Link Aggregation");
 
-static int lagg_failover_rx_all = 0; /* Allow input on any failover links */
-SYSCTL_INT(_net_link_lagg, OID_AUTO, failover_rx_all, CTLFLAG_RW,
-    &lagg_failover_rx_all, 0,
+/* Allow input on any failover links */
+static VNET_DEFINE(int, lagg_failover_rx_all);
+#define        V_lagg_failover_rx_all  VNET(lagg_failover_rx_all)
+SYSCTL_INT(_net_link_lagg, OID_AUTO, failover_rx_all, CTLFLAG_RW | 
CTLFLAG_VNET,
+    &VNET_NAME(lagg_failover_rx_all), 0,
     "Accept input from any interface in a failover lagg");
-static int def_use_flowid = 1; /* Default value for using M_FLOWID */
+
+/* Default value for using M_FLOWID */
+static VNET_DEFINE(int, def_use_flowid) = 1;
+#define        V_def_use_flowid        VNET(def_use_flowid)
 SYSCTL_INT(_net_link_lagg, OID_AUTO, default_use_flowid, CTLFLAG_RWTUN,
-    &def_use_flowid, 0,
+    &VNET_NAME(def_use_flowid), 0,
     "Default setting for using flow id for load sharing");
-static int def_flowid_shift = 16; /* Default value for using M_FLOWID */
+
+/* Default value for using M_FLOWID */
+static VNET_DEFINE(int, def_flowid_shift) = 16;
+#define        V_def_flowid_shift      VNET(def_flowid_shift)
 SYSCTL_INT(_net_link_lagg, OID_AUTO, default_flowid_shift, CTLFLAG_RWTUN,
-    &def_flowid_shift, 0,
+    &VNET_NAME(def_flowid_shift), 0,
     "Default setting for flowid shift for load sharing");
 
+static void
+vnet_lagg_init(const void *unused __unused)
+{
+
+       LAGG_LIST_LOCK_INIT();
+       SLIST_INIT(&V_lagg_list);
+       V_lagg_cloner = if_clone_simple(laggname, lagg_clone_create,
+           lagg_clone_destroy, 0);
+}
+VNET_SYSINIT(vnet_lagg_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
+    vnet_lagg_init, NULL);
+
+static void
+vnet_lagg_uninit(const void *unused __unused)
+{
+
+       if_clone_detach(V_lagg_cloner);
+       LAGG_LIST_LOCK_DESTROY();
+}
+VNET_SYSUNINIT(vnet_lagg_uninit, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
+    vnet_lagg_uninit, NULL);
+
 static int
 lagg_modevent(module_t mod, int type, void *data)
 {
 
        switch (type) {
        case MOD_LOAD:
-               mtx_init(&lagg_list_mtx, "if_lagg list", NULL, MTX_DEF);
-               SLIST_INIT(&lagg_list);
-               lagg_cloner = if_clone_simple(laggname, lagg_clone_create,
-                   lagg_clone_destroy, 0);
                lagg_input_p = lagg_input;
                lagg_linkstate_p = lagg_port_state;
                lagg_detach_cookie = EVENTHANDLER_REGISTER(
@@ -264,10 +298,8 @@ lagg_modevent(module_t mod, int type, vo
        case MOD_UNLOAD:
                EVENTHANDLER_DEREGISTER(ifnet_departure_event,
                    lagg_detach_cookie);
-               if_clone_detach(lagg_cloner);
                lagg_input_p = NULL;
                lagg_linkstate_p = NULL;
-               mtx_destroy(&lagg_list_mtx);
                break;
        default:
                return (EOPNOTSUPP);
@@ -445,8 +477,6 @@ lagg_clone_create(struct if_clone *ifc, 
        struct lagg_softc *sc;
        struct ifnet *ifp;
        static const u_char eaddr[6];   /* 00:00:00:00:00:00 */
-       struct sysctl_oid *oid;
-       char num[14];                   /* sufficient for 32 bits */
 
        sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO);
        ifp = sc->sc_ifp = if_alloc(IFT_ETHER);
@@ -455,29 +485,10 @@ lagg_clone_create(struct if_clone *ifc, 
                return (ENOSPC);
        }
 
-       sysctl_ctx_init(&sc->ctx);
-       snprintf(num, sizeof(num), "%u", unit);
-       sc->use_flowid = def_use_flowid;
-       sc->flowid_shift = def_flowid_shift;
-       sc->sc_oid = oid = SYSCTL_ADD_NODE(&sc->ctx,
-               &SYSCTL_NODE_CHILDREN(_net_link, lagg),
-               OID_AUTO, num, CTLFLAG_RD, NULL, "");
-       SYSCTL_ADD_INT(&sc->ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
-               "use_flowid", CTLTYPE_INT|CTLFLAG_RW, &sc->use_flowid,
-               sc->use_flowid, "Use flow id for load sharing");
-       SYSCTL_ADD_INT(&sc->ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
-               "flowid_shift", CTLTYPE_INT|CTLFLAG_RW, &sc->flowid_shift,
-               sc->flowid_shift,
-               "Shift flowid bits to prevent multiqueue collisions");
-       SYSCTL_ADD_INT(&sc->ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
-               "count", CTLTYPE_INT|CTLFLAG_RD, &sc->sc_count, sc->sc_count,
-               "Total number of ports");
-       SYSCTL_ADD_PROC(&sc->ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
-               "active", CTLTYPE_INT|CTLFLAG_RD, sc, 0, lagg_sysctl_active,
-               "I", "Total number of active ports");
-       SYSCTL_ADD_INT(&sc->ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
-               "flapping", CTLTYPE_INT|CTLFLAG_RD, &sc->sc_flapping,
-               sc->sc_flapping, "Total number of port change events");
+       if (V_def_use_flowid)
+               sc->sc_opts |= LAGG_OPT_USE_FLOWID;
+       sc->flowid_shift = V_def_flowid_shift;
+
        /* Hash all layers by default */
        sc->sc_flags = LAGG_F_HASHL2|LAGG_F_HASHL3|LAGG_F_HASHL4;
 
@@ -515,9 +526,9 @@ lagg_clone_create(struct if_clone *ifc, 
                lagg_unregister_vlan, sc, EVENTHANDLER_PRI_FIRST);
 
        /* Insert into the global list of laggs */
-       mtx_lock(&lagg_list_mtx);
-       SLIST_INSERT_HEAD(&lagg_list, sc, sc_entries);
-       mtx_unlock(&lagg_list_mtx);
+       LAGG_LIST_LOCK();
+       SLIST_INSERT_HEAD(&V_lagg_list, sc, sc_entries);
+       LAGG_LIST_UNLOCK();
 
        return (0);
 }
@@ -542,14 +553,13 @@ lagg_clone_destroy(struct ifnet *ifp)
        /* Unhook the aggregation protocol */
        lagg_proto_detach(sc);
 
-       sysctl_ctx_free(&sc->ctx);
        ifmedia_removeall(&sc->sc_media);
        ether_ifdetach(ifp);
        if_free(ifp);
 
-       mtx_lock(&lagg_list_mtx);
-       SLIST_REMOVE(&lagg_list, sc, lagg_softc, sc_entries);
-       mtx_unlock(&lagg_list_mtx);
+       LAGG_LIST_LOCK();
+       SLIST_REMOVE(&V_lagg_list, sc, lagg_softc, sc_entries);
+       LAGG_LIST_UNLOCK();
 
        taskqueue_drain(taskqueue_swi, &sc->sc_lladdr_task);
        LAGG_LOCK_DESTROY(sc);
@@ -752,10 +762,10 @@ lagg_port_create(struct lagg_softc *sc, 
                return (ENOMEM);
 
        /* Check if port is a stacked lagg */
-       mtx_lock(&lagg_list_mtx);
-       SLIST_FOREACH(sc_ptr, &lagg_list, sc_entries) {
+       LAGG_LIST_LOCK();
+       SLIST_FOREACH(sc_ptr, &V_lagg_list, sc_entries) {
                if (ifp == sc_ptr->sc_ifp) {
-                       mtx_unlock(&lagg_list_mtx);
+                       LAGG_LIST_UNLOCK();
                        free(lp, M_DEVBUF);
                        return (EINVAL);
                        /* XXX disable stacking for the moment, its untested */
@@ -763,14 +773,14 @@ lagg_port_create(struct lagg_softc *sc, 
                        lp->lp_flags |= LAGG_PORT_STACK;
                        if (lagg_port_checkstacking(sc_ptr) >=
                            LAGG_MAX_STACKING) {
-                               mtx_unlock(&lagg_list_mtx);
+                               LAGG_LIST_UNLOCK();
                                free(lp, M_DEVBUF);
                                return (E2BIG);
                        }
 #endif
                }
        }
-       mtx_unlock(&lagg_list_mtx);
+       LAGG_LIST_UNLOCK();
 
        /* Change the interface type */
        lp->lp_iftype = ifp->if_type;
@@ -1205,6 +1215,31 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd
                LAGG_RLOCK(sc, &tracker);
                ra->ra_proto = sc->sc_proto;
                lagg_proto_request(sc, &ra->ra_psc);
+               ra->ra_opts = sc->sc_opts;
+               if (sc->sc_proto == LAGG_PROTO_LACP) {
+                       struct lacp_softc *lsc;
+
+                       lsc = (struct lacp_softc *)sc->sc_psc;
+                       if (lsc->lsc_debug.lsc_tx_test != 0)
+                               ra->ra_opts |= LAGG_OPT_LACP_TXTEST;
+                       if (lsc->lsc_debug.lsc_rx_test != 0)
+                               ra->ra_opts |= LAGG_OPT_LACP_RXTEST;
+                       if (lsc->lsc_strict_mode != 0)
+                               ra->ra_opts |= LAGG_OPT_LACP_STRICT;
+
+                       ra->ra_active = sc->sc_active;
+               } else {
+                       /*
+                        * LACP tracks active links automatically,
+                        * the others do not.
+                        */
+                       ra->ra_active = 0;
+                       SLIST_FOREACH(lp, &sc->sc_ports, lp_entries)
+                               ra->ra_active += LAGG_PORTACTIVE(lp);
+               }
+               ra->ra_flapping = sc->sc_flapping;
+               ra->ra_flowid_shift = sc->flowid_shift;
+
                count = 0;
                buf = outbuf;
                len = min(ra->ra_size, buflen);
@@ -1225,9 +1260,88 @@ lagg_ioctl(struct ifnet *ifp, u_long cmd
                free(outbuf, M_TEMP);
                break;
        case SIOCSLAGG:
+               /*
+                * Set options or protocol depending on
+                * ra->ra_opts and ra->ra_proto.
+                */
                error = priv_check(td, PRIV_NET_LAGG);
                if (error)
                        break;
+               if (ra->ra_opts != 0) {
+                       /*
+                        * Set options.  LACP options are stored in sc->sc_psc,
+                        * not in sc_opts.
+                        */
+                       int valid, lacp;
+
+                       switch (ra->ra_opts) {
+                       case LAGG_OPT_USE_FLOWID:
+                       case -LAGG_OPT_USE_FLOWID:
+                       case LAGG_OPT_FLOWIDSHIFT:
+                               valid = 1;
+                               lacp = 0;
+                               break;
+                       case LAGG_OPT_LACP_TXTEST:
+                       case -LAGG_OPT_LACP_TXTEST:
+                       case LAGG_OPT_LACP_RXTEST:
+                       case -LAGG_OPT_LACP_RXTEST:
+                       case LAGG_OPT_LACP_STRICT:
+                       case -LAGG_OPT_LACP_STRICT:
+                               valid = lacp = 1;
+                               break;
+                       default:
+                               valid = lacp = 0;
+                               break;
+                       }
+
+                       LAGG_WLOCK(sc);
+                       if (valid == 0 ||
+                           (lacp == 1 && sc->sc_proto != LAGG_PROTO_LACP)) {
+                               /* Invalid combination of options specified. */
+                               error = EINVAL;
+                               LAGG_WUNLOCK(sc);
+                               break;  /* Return from SIOCSLAGG. */ 
+                       }
+                       /*
+                        * Store new options into sc->sc_opts except for
+                        * FLOWIDSHIFT and LACP options.
+                        */
+                       if (lacp == 0) {
+                               if (ra->ra_opts == LAGG_OPT_FLOWIDSHIFT)
+                                       sc->flowid_shift = ra->ra_flowid_shift;
+                               else if (ra->ra_opts > 0)
+                                       sc->sc_opts |= ra->ra_opts;
+                               else
+                                       sc->sc_opts &= ~ra->ra_opts;
+                       } else {
+                               struct lacp_softc *lsc;
+
+                               lsc = (struct lacp_softc *)sc->sc_psc;
+
+                               switch (ra->ra_opts) {
+                               case LAGG_OPT_LACP_TXTEST:
+                                       lsc->lsc_debug.lsc_tx_test = 1;
+                                       break;
+                               case -LAGG_OPT_LACP_TXTEST:
+                                       lsc->lsc_debug.lsc_tx_test = 0;
+                                       break;
+                               case LAGG_OPT_LACP_RXTEST:
+                                       lsc->lsc_debug.lsc_rx_test = 1;
+                                       break;
+                               case -LAGG_OPT_LACP_RXTEST:
+                                       lsc->lsc_debug.lsc_rx_test = 0;
+                                       break;
+                               case LAGG_OPT_LACP_STRICT:
+                                       lsc->lsc_strict_mode = 1;
+                                       break;
+                               case -LAGG_OPT_LACP_STRICT:
+                                       lsc->lsc_strict_mode = 0;
+                                       break;
+                               }
+                       }
+                       LAGG_WUNLOCK(sc);
+                       break;  /* Return from SIOCSLAGG. */ 
+               }
                if (ra->ra_proto < 1 || ra->ra_proto >= LAGG_PROTO_MAX) {
                        error = EPROTONOSUPPORT;
                        break;
@@ -1687,27 +1801,6 @@ lagg_gethdr(struct mbuf *m, u_int off, u
        return (mtod(m, char *) + off);
 }
 
-static int
-lagg_sysctl_active(SYSCTL_HANDLER_ARGS)
-{
-       struct lagg_softc *sc = (struct lagg_softc *)arg1;
-       struct lagg_port *lp;
-       int error;
-
-       /* LACP tracks active links automatically, the others do not */
-       if (sc->sc_proto != LAGG_PROTO_LACP) {
-               sc->sc_active = 0;
-               SLIST_FOREACH(lp, &sc->sc_ports, lp_entries)
-                       sc->sc_active += LAGG_PORTACTIVE(lp);
-       }
-
-       error = sysctl_handle_int(oidp, &sc->sc_active, 0, req);
-       if ((error) || (req->newptr == NULL))
-               return (error);
-
-       return (0);
-}
-
 uint32_t
 lagg_hashmbuf(struct lagg_softc *sc, struct mbuf *m, uint32_t key)
 {
@@ -1948,7 +2041,7 @@ lagg_fail_input(struct lagg_softc *sc, s
        struct ifnet *ifp = sc->sc_ifp;
        struct lagg_port *tmp_tp;
 
-       if (lp == sc->sc_primary || lagg_failover_rx_all) {
+       if (lp == sc->sc_primary || V_lagg_failover_rx_all) {
                m->m_pkthdr.rcvif = ifp;
                return (m);
        }
@@ -2043,7 +2136,7 @@ lagg_lb_start(struct lagg_softc *sc, str
        struct lagg_port *lp = NULL;
        uint32_t p = 0;
 
-       if (sc->use_flowid && (m->m_flags & M_FLOWID))
+       if ((sc->sc_opts & LAGG_OPT_USE_FLOWID) && (m->m_flags & M_FLOWID))
                p = m->m_pkthdr.flowid >> sc->flowid_shift;
        else
                p = lagg_hashmbuf(sc, m, lb->lb_key);

Modified: head/sys/net/if_lagg.h
==============================================================================
--- head/sys/net/if_lagg.h      Wed Oct  1 21:24:58 2014        (r272385)
+++ head/sys/net/if_lagg.h      Wed Oct  1 21:37:32 2014        (r272386)
@@ -125,6 +125,19 @@ struct lagg_reqall {
                struct lacp_opreq rpsc_lacp;
        } ra_psc;
 #define ra_lacpreq     ra_psc.rpsc_lacp
+       int                     ra_opts;                /* Option bitmap */
+#define        LAGG_OPT_NONE                   0x00
+#define        LAGG_OPT_USE_FLOWID             0x01            /* use M_FLOWID 
*/
+/* Pseudo flags which are used in ra_opts but not stored into sc_opts. */
+#define        LAGG_OPT_FLOWIDSHIFT            0x02            /* Set flowid */
+#define        LAGG_OPT_FLOWIDSHIFT_MASK       0x1f            /* flowid is 
uint32_t */
+#define        LAGG_OPT_LACP_STRICT            0x10            /* LACP strict 
mode */
+#define        LAGG_OPT_LACP_TXTEST            0x20            /* LACP debug: 
txtest */
+#define        LAGG_OPT_LACP_RXTEST            0x40            /* LACP debug: 
rxtest */
+       u_int                   ra_count;               /* number of ports */
+       u_int                   ra_active;              /* active port count */
+       u_int                   ra_flapping;            /* number of flapping */
+       int                     ra_flowid_shift;        /* shift the flowid */
 };
 
 #define        SIOCGLAGG               _IOWR('i', 143, struct lagg_reqall)
@@ -212,9 +225,7 @@ struct lagg_softc {
        eventhandler_tag vlan_attach;
        eventhandler_tag vlan_detach;
        struct callout                  sc_callout;
-       struct sysctl_ctx_list          ctx;            /* sysctl variables */
-       struct sysctl_oid               *sc_oid;        /* sysctl tree oid */
-       int                             use_flowid;     /* use M_FLOWID */
+       u_int                           sc_opts;
        int                             flowid_shift;   /* shift the flowid */
        struct lagg_counters            detached_counters; /* detached ports 
sum */
 };
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to