Module Name: src Committed By: dyoung Date: Wed Oct 19 01:34:37 UTC 2011
Modified Files: src/sys/net: if.c if.h Log Message: 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. To generate a diff of this commit: cvs rdiff -u -r1.251 -r1.252 src/sys/net/if.c cvs rdiff -u -r1.151 -r1.152 src/sys/net/if.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/net/if.c diff -u src/sys/net/if.c:1.251 src/sys/net/if.c:1.252 --- src/sys/net/if.c:1.251 Fri Aug 12 22:09:36 2011 +++ src/sys/net/if.c Wed Oct 19 01:34:37 2011 @@ -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 @@ struct pfil_head if_pfil; /* packet filt 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 @@ int if_nullioctl(struct ifnet *ifp, u_long cmd, void *data) { + cv_signal(&ifp->if_ioctl_emptied); return ENXIO; } @@ -497,8 +500,8 @@ if_attach(struct ifnet *ifp) } 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 @@ again: TAILQ_REMOVE(&ifnet, ifp, if_list); + ifioctl_detach(ifp); + /* * remove packets that came from ifp, from software interrupt queues. */ @@ -1403,8 +1408,7 @@ int 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 @@ ifpromisc(struct ifnet *ifp, int pswitch */ 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 @@ ifioctl(struct socket *so, u_long cmd, v 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 @@ ifioctl(struct socket *so, u_long cmd, v 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 @@ ifq_enqueue2(struct ifnet *ifp, struct i 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, Index: src/sys/net/if.h diff -u src/sys/net/if.h:1.151 src/sys/net/if.h:1.152 --- src/sys/net/if.h:1.151 Fri Aug 12 22:09:17 2011 +++ src/sys/net/if.h Wed Oct 19 01:34:37 2011 @@ -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 @@ typedef struct ifnet { * 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(struct socket *, u_long, voi 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 *);