Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/net Start to untangle the ifnet ioctls mess.



details:   https://anonhg.NetBSD.org/src/rev/3863ecabfadb
branches:  trunk
changeset: 770496:3863ecabfadb
user:      dyoung <dyoung%NetBSD.org@localhost>
date:      Wed Oct 19 01:34:37 2011 +0000

description:
Start to untangle the ifnet ioctls mess.

Add ifnet functions, if_mcast_op(), if_flags_set(), and if_addr_init()
for adding/deleting multicast addresses, modifying the if_flags,
and initializing local/remote addresses.  Make ifpromisc() use
if_flags_set().  Protocols and network drivers should use these
instead of ifp->if_ioctl() calls.  Subsequent commits will
replace ifp->if_ioctl(SIOCADDMULTI| SIOCDELMULTI| SIOCSIFDSTADDR|
SIOCINITIFADDR| SIOCSIFFLAGS) calls with calls to the new functions.

Use a mutex(9) to synchronize ifp->if_ioctl() calls originating in
userland.  Also synchronize ifp->if_ioctl() calls with ifnet detachment
and reclamation.

diffstat:

 sys/net/if.c |  127 ++++++++++++++++++++++++++++++++++++++++++++++++++++------
 sys/net/if.h |   18 +++++++-
 2 files changed, 129 insertions(+), 16 deletions(-)

diffs (279 lines):

diff -r 0e19e296c511 -r 3863ecabfadb sys/net/if.c
--- a/sys/net/if.c      Wed Oct 19 00:27:40 2011 +0000
+++ b/sys/net/if.c      Wed Oct 19 01:34:37 2011 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if.c,v 1.251 2011/08/12 22:09:36 dyoung Exp $  */
+/*     $NetBSD: if.c,v 1.252 2011/10/19 01:34:37 dyoung Exp $  */
 
 /*-
  * Copyright (c) 1999, 2000, 2001, 2008 The NetBSD Foundation, Inc.
@@ -90,7 +90,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.251 2011/08/12 22:09:36 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.252 2011/10/19 01:34:37 dyoung Exp $");
 
 #include "opt_inet.h"
 
@@ -168,6 +168,8 @@
 
 static kauth_listener_t if_listener;
 
+static int ifioctl_attach(struct ifnet *);
+static void ifioctl_detach(struct ifnet *);
 static void if_detach_queues(struct ifnet *, struct ifqueue *);
 static void sysctl_sndq_setup(struct sysctllog **, const char *,
     struct ifaltq *);
@@ -292,6 +294,7 @@
 if_nullioctl(struct ifnet *ifp, u_long cmd, void *data)
 {
 
+       cv_signal(&ifp->if_ioctl_emptied);
        return ENXIO;
 }
 
@@ -497,8 +500,8 @@
        }
        TAILQ_INIT(&ifp->if_addrlist);
        TAILQ_INSERT_TAIL(&ifnet, ifp, if_list);
-       if (ifp->if_ioctl == NULL)
-               ifp->if_ioctl = ifioctl_common;
+
+       ifioctl_attach(ifp);    /* XXX ifioctl_attach can fail! */ 
 
        mutex_enter(&index_gen_mtx);
        ifp->if_index_gen = index_gen++;
@@ -842,6 +845,8 @@
 
        TAILQ_REMOVE(&ifnet, ifp, if_list);
 
+       ifioctl_detach(ifp);
+
        /*
         * remove packets that came from ifp, from software interrupt queues.
         */
@@ -1403,8 +1408,7 @@
 ifpromisc(struct ifnet *ifp, int pswitch)
 {
        int pcount, ret;
-       short flags;
-       struct ifreq ifr;
+       short flags, nflags;
 
        pcount = ifp->if_pcount;
        flags = ifp->if_flags;
@@ -1416,29 +1420,26 @@
                 */
                if (ifp->if_pcount++ != 0)
                        return 0;
-               ifp->if_flags |= IFF_PROMISC;
-               if ((ifp->if_flags & IFF_UP) == 0)
+               nflags = ifp->if_flags | IFF_PROMISC;
+               if ((nflags & IFF_UP) == 0)
                        return 0;
        } else {
                if (--ifp->if_pcount > 0)
                        return 0;
-               ifp->if_flags &= ~IFF_PROMISC;
+               nflags = ifp->if_flags & ~IFF_PROMISC;
                /*
                 * If the device is not configured up, we should not need to
                 * turn off promiscuous mode (device should have turned it
                 * off when interface went down; and will look at IFF_PROMISC
                 * again next time interface comes up).
                 */
-               if ((ifp->if_flags & IFF_UP) == 0)
+               if ((nflags & IFF_UP) == 0)
                        return 0;
        }
-       memset(&ifr, 0, sizeof(ifr));
-       ifr.ifr_flags = ifp->if_flags;
-       ret = (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, &ifr);
+       ret = if_flags_set(ifp, nflags);
        /* Restore interface state if not successful. */
        if (ret != 0) {
                ifp->if_pcount = pcount;
-               ifp->if_flags = flags;
        }
        return ret;
 }
@@ -1801,11 +1802,15 @@
 
        oif_flags = ifp->if_flags;
 
+       uint64_t *nenter = percpu_getref(ifp->if_ioctl_nenter);
+       (*nenter)++;
+       percpu_putref(ifp->if_ioctl_nenter);
+       mutex_enter(&ifp->if_ioctl_lock);
        error = (*ifp->if_ioctl)(ifp, cmd, data);
        if (error != ENOTTY)
                ;
        else if (so->so_proto == NULL)
-               return EOPNOTSUPP;
+               error = EOPNOTSUPP;
        else {
 #ifdef COMPAT_OSOCK
                error = compat_ifioctl(so, ocmd, cmd, data, l);
@@ -1830,9 +1835,55 @@
                ifreqn2o(oifr, ifr);
 #endif
 
+       ifp->if_ioctl_nexit++;
+       mutex_exit(&ifp->if_ioctl_lock);
        return error;
 }
 
+static void
+ifioctl_sum(void *p, void *arg, struct cpu_info *ci)
+{
+       uint64_t *sum = arg, *nenter = p;
+
+       *sum += *nenter;
+}
+
+static uint64_t
+ifioctl_entrances(struct ifnet *ifp)
+{
+       uint64_t sum = 0;
+
+       percpu_foreach(ifp->if_ioctl_nenter, ifioctl_sum, &sum);
+
+       return sum;
+}
+
+static int
+ifioctl_attach(struct ifnet *ifp)
+{
+       if (ifp->if_ioctl == NULL)
+               ifp->if_ioctl = ifioctl_common;
+
+       ifp->if_ioctl_nenter = percpu_alloc(sizeof(uint64_t));
+       if (ifp->if_ioctl_nenter == NULL)
+               return ENOMEM;
+
+       mutex_init(&ifp->if_ioctl_lock, MUTEX_DEFAULT, IPL_NONE);
+       cv_init(&ifp->if_ioctl_emptied, ifp->if_xname);
+
+       return 0;
+}
+
+static void
+ifioctl_detach(struct ifnet *ifp)
+{
+       mutex_enter(&ifp->if_ioctl_lock);
+       ifp->if_ioctl = if_nullioctl;
+       while (ifioctl_entrances(ifp) != ifp->if_ioctl_nexit)
+               cv_wait(&ifp->if_ioctl_emptied, &ifp->if_ioctl_lock);
+       mutex_exit(&ifp->if_ioctl_lock);
+}
+
 /*
  * Return interface configuration
  * of system.  List may be used
@@ -2012,6 +2063,52 @@
        return 0;
 }
 
+int
+if_addr_init(ifnet_t *ifp, struct ifaddr *ifa, const bool src)
+{
+       int rc;
+
+       if (ifp->if_initaddr != NULL)
+               rc = (*ifp->if_initaddr)(ifp, ifa, src);
+       else if (src ||
+                (rc = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ifa)) == ENOTTY)
+               rc = (*ifp->if_ioctl)(ifp, SIOCINITIFADDR, ifa);
+
+       return rc;
+}
+
+int
+if_flags_set(ifnet_t *ifp, const short flags)
+{
+       int rc;
+       struct ifreq ifr;
+
+       if (ifp->if_setflags != NULL)
+               rc = (*ifp->if_setflags)(ifp, flags);
+       else {
+               memset(&ifr, 0, sizeof(ifr));
+               ifr.ifr_flags = flags;
+               rc = (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, &ifr);
+       }
+
+       return rc;
+}
+
+int
+if_mcast_op(ifnet_t *ifp, const unsigned long cmd, const struct sockaddr *sa)
+{
+       int rc;
+       struct ifreq ifr;
+
+       if (ifp->if_mcastop != NULL)
+               rc = (*ifp->if_mcastop)(ifp, cmd, sa);
+       else {
+               ifreq_setaddr(cmd, &ifr, sa);
+               rc = (*ifp->if_ioctl)(ifp, cmd, &ifr);
+       }
+
+       return rc;
+}
 
 static void
 sysctl_sndq_setup(struct sysctllog **clog, const char *ifname,
diff -r 0e19e296c511 -r 3863ecabfadb sys/net/if.h
--- a/sys/net/if.h      Wed Oct 19 00:27:40 2011 +0000
+++ b/sys/net/if.h      Wed Oct 19 01:34:37 2011 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if.h,v 1.151 2011/08/12 22:09:17 dyoung Exp $  */
+/*     $NetBSD: if.h,v 1.152 2011/10/19 01:34:37 dyoung Exp $  */
 
 /*-
  * Copyright (c) 1999, 2000, 2001 The NetBSD Foundation, Inc.
@@ -63,6 +63,10 @@
 #ifndef _NET_IF_H_
 #define _NET_IF_H_
 
+#if !defined(_KERNEL) && !defined(_STANDALONE)
+#include <stdbool.h>
+#endif
+
 #include <sys/featuretest.h>
 
 /*
@@ -75,6 +79,7 @@
 
 #include <sys/mutex.h>
 #include <sys/condvar.h>
+#include <sys/percpu.h>
 #include <sys/socket.h>
 #include <sys/queue.h>
 #include <net/dlt.h>
@@ -296,6 +301,14 @@
                                         * same, they are the same ifnet.
                                         */
        struct sysctllog        *if_sysctl_log;
+       int (*if_initaddr)(struct ifnet *, struct ifaddr *, bool);
+       int (*if_mcastop)(struct ifnet *, const unsigned long,
+           const struct sockaddr *);
+       int (*if_setflags)(struct ifnet *, const short);
+       kmutex_t if_ioctl_lock;
+       uint64_t if_ioctl_nexit;
+       percpu_t *if_ioctl_nenter;
+       kcondvar_t if_ioctl_emptied;
 } ifnet_t;
 
 #define        if_mtu          if_data.ifi_mtu
@@ -850,6 +863,9 @@
 int    ifioctl_common(struct ifnet *, u_long, void *);
 int    ifpromisc(struct ifnet *, int);
 struct ifnet *ifunit(const char *);
+int    if_addr_init(ifnet_t *, struct ifaddr *, bool);
+int    if_mcast_op(ifnet_t *, const unsigned long, const struct sockaddr *);
+int    if_flags_set(struct ifnet *, const short);
 
 void ifa_insert(struct ifnet *, struct ifaddr *);
 void ifa_remove(struct ifnet *, struct ifaddr *);



Home | Main Index | Thread Index | Old Index