net: Implement interface group support
authorAaron LI <aly@aaronly.me>
Sat, 16 Jun 2018 14:25:31 +0000 (22:25 +0800)
committerAaron LI <aly@aaronly.me>
Wed, 8 Aug 2018 08:37:19 +0000 (16:37 +0800)
The network interface group (aka ifgroup) functionality is currently only
used by the PF (still needs patch to make PF use the ifgroup), allowing
rules to use group names instead of the specific interface names, which
makes firewall rules more generic and simpler.

* The ifgroup data are stored at the following two places:
  - The global list of 'struct ifg_group': each entry is a group which has
    the name and members (a list of pointers to the interfaces).
  - The per-ifnet 'if_groups' list, which records the groups that the
    interface belongs to.

* Introduce the 'ifgroup_lock' locakmgr(9) to protect the global list
  of 'struct ifg_group' and per-ifnet 'if_groups' list.  The R/W locking
  operations are provided by the ifgroup_lockmgr() function.

* Move the copyout() out of the locked loop in if_getgroups() and
  if_getgroupmembers() functions.

* Fix several M_NOWAIT to be M_WAITOK.

* Use M_IFNET instead of M_TEMP for allocated ifgroup memory.

* Add SIOC[ADG]IFGROUP and SIOCGIFGMEMB ioctl's,
  bump __DragonFly_version.

* Add invocations to group_{attach,change,detach}_event handlers.

* Update eventhandler.9 man page.

* Some style updates.

Great thanks to sephe for his patient guidance and review.

Credit to both FreeBSD and OpenBSD for the ifgroup functionality.

NOTE:
When delete the only group from an interface, which leaves an empty
group that will be destroyed, make sure the group_change_event event
is invoked *before* the group destroy (i.e., group_detach_event).
Both FreeBSD and OpenBSD have the ordering problem with group detach
event.  Need to report the problem to them.

share/man/man9/EVENTHANDLER.9
sys/net/if.c
sys/net/if.h
sys/net/if_var.h
sys/sys/param.h
sys/sys/sockio.h

index 2af0f9f..7516f87 100644 (file)
@@ -25,7 +25,7 @@
 .\"
 .\" $FreeBSD: src/share/man/man9/EVENTHANDLER.9,v 1.4 2005/10/11 16:05:35 keramida Exp $
 .\"
-.Dd June 21, 2018
+.Dd June 22, 2018
 .Dt EVENTHANDLER 9
 .Os
 .Sh NAME
@@ -190,6 +190,12 @@ Callbacks invoked when the system is being woken up.
 .It Vt dev_clone
 Callbacks invoked when a new entry is created under
 .Pa /dev .
+.It Vt group_attach_event
+Callbacks invoked when a new interface group has been created.
+.It Vt group_change_event
+Callbacks invoked when the members of an interface group have changed.
+.It Vt group_detach_event
+Callbacks invoked when an interface group has been removed due to no members.
 .It Vt if_clone_event
 Callbacks invoked when a new interface cloner is attached.
 .It Vt ifaddr_event
index b3c2596..a97cd7f 100644 (file)
@@ -47,6 +47,7 @@
 #include <sys/kernel.h>
 #include <sys/ktr.h>
 #include <sys/mutex.h>
+#include <sys/lock.h>
 #include <sys/sockio.h>
 #include <sys/syslog.h>
 #include <sys/sysctl.h>
 #include <machine/smp.h>
 
 #if defined(INET) || defined(INET6)
-/*XXX*/
 #include <netinet/in.h>
 #include <netinet/in_var.h>
 #include <netinet/if_ether.h>
 #ifdef INET6
 #include <netinet6/in6_var.h>
 #include <netinet6/in6_ifattach.h>
-#endif
-#endif
+#endif /* INET6 */
+#endif /* INET || INET6 */
 
 struct netmsg_ifaddr {
        struct netmsg_base base;
@@ -130,6 +130,11 @@ static struct ifnet_array *ifnet_array_add(struct ifnet *,
                    const struct ifnet_array *);
 static struct ifnet_array *ifnet_array_del(struct ifnet *,
                    const struct ifnet_array *);
+static struct ifg_group *if_creategroup(const char *);
+static int     if_destroygroup(struct ifg_group *);
+static int     if_delgroup_locked(struct ifnet *, const char *);
+static int     if_getgroups(struct ifgroupreq *, struct ifnet *);
+static int     if_getgroupmembers(struct ifgroupreq *);
 
 #ifdef INET6
 /*
@@ -168,6 +173,8 @@ MALLOC_DEFINE(M_IFNET, "ifnet", "interface structure");
 
 int                    ifqmaxlen = IFQ_MAXLEN;
 struct ifnethead       ifnet = TAILQ_HEAD_INITIALIZER(ifnet);
+struct ifgrouphead     ifg_head = TAILQ_HEAD_INITIALIZER(ifg_head);
+static struct lock     ifgroup_lock;
 
 static struct ifnet_array      ifnet_array0;
 static struct ifnet_array      *ifnet_array = &ifnet_array0;
@@ -209,9 +216,7 @@ KTR_INFO(KTR_IF_START, if_start, contend_sched, 3,
 KTR_INFO(KTR_IF_START, if_start, chase_sched, 4,
         IF_START_KTR_STRING, IF_START_KTR_ARGS);
 #define logifstart(name, arg)  KTR_LOG(if_start_ ## name, arg)
-#endif
-
-TAILQ_HEAD(, ifg_group) ifg_head = TAILQ_HEAD_INITIALIZER(ifg_head);
+#endif /* notyet */
 
 /*
  * Network interface utility routines.
@@ -223,6 +228,7 @@ TAILQ_HEAD(, ifg_group) ifg_head = TAILQ_HEAD_INITIALIZER(ifg_head);
 static void
 ifinit(void *dummy)
 {
+       lockinit(&ifgroup_lock, "ifgroup", 0, 0);
 
        callout_init_mp(&if_slowtimo_timer);
        netmsg_init(&if_slowtimo_netmsg, NULL, &netisr_adone_rport,
@@ -528,6 +534,7 @@ if_attach(struct ifnet *ifp, lwkt_serialize_t serializer)
        TAILQ_INIT(&ifp->if_multiaddrs);
        TAILQ_INIT(&ifp->if_groups);
        getmicrotime(&ifp->if_lastchange);
+       if_addgroup(ifp, IFG_ALL);
 
        /*
         * create a Link Level name for this device
@@ -919,6 +926,7 @@ void
 if_detach(struct ifnet *ifp)
 {
        struct ifnet_array *old_ifnet_array;
+       struct ifg_list *ifgl;
        struct netmsg_if_rtdel msg;
        struct domain *dp;
        int q;
@@ -959,6 +967,11 @@ if_detach(struct ifnet *ifp)
 
        ifnet_unlock();
 
+       ifgroup_lockmgr(LK_EXCLUSIVE);
+       while ((ifgl = TAILQ_FIRST(&ifp->if_groups)) != NULL)
+               if_delgroup_locked(ifp, ifgl->ifgl_group->ifg_group);
+       ifgroup_lockmgr(LK_RELEASE);
+
        /*
         * Sync all netisrs so that the old ifnet array is no longer
         * accessed and we can free it safely later on.
@@ -1056,197 +1069,280 @@ if_detach(struct ifnet *ifp)
        crit_exit();
 }
 
+int
+ifgroup_lockmgr(u_int flags)
+{
+       return lockmgr(&ifgroup_lock, flags);
+}
+
 /*
- * Create interface group without members
+ * Create an empty interface group.
  */
-struct ifg_group *
+static struct ifg_group *
 if_creategroup(const char *groupname)
 {
-        struct ifg_group        *ifg = NULL;
+       struct ifg_group *ifg;
 
-        if ((ifg = (struct ifg_group *)kmalloc(sizeof(struct ifg_group),
-            M_TEMP, M_NOWAIT)) == NULL)
-                return (NULL);
+       ifg = kmalloc(sizeof(*ifg), M_IFNET, M_WAITOK);
+       strlcpy(ifg->ifg_group, groupname, sizeof(ifg->ifg_group));
+       ifg->ifg_refcnt = 0;
+       ifg->ifg_carp_demoted = 0;
+       TAILQ_INIT(&ifg->ifg_members);
 
-        strlcpy(ifg->ifg_group, groupname, sizeof(ifg->ifg_group));
-        ifg->ifg_refcnt = 0;
-        ifg->ifg_carp_demoted = 0;
-        TAILQ_INIT(&ifg->ifg_members);
-#if NPF > 0
-        pfi_attach_ifgroup(ifg);
-#endif
-        TAILQ_INSERT_TAIL(&ifg_head, ifg, ifg_next);
+       ifgroup_lockmgr(LK_EXCLUSIVE);
+       TAILQ_INSERT_TAIL(&ifg_head, ifg, ifg_next);
+       ifgroup_lockmgr(LK_RELEASE);
+
+       EVENTHANDLER_INVOKE(group_attach_event, ifg);
 
-        return (ifg);
+       return (ifg);
 }
 
 /*
- * Add a group to an interface
+ * Destroy an empty interface group.
+ */
+static int
+if_destroygroup(struct ifg_group *ifg)
+{
+       KASSERT(ifg->ifg_refcnt == 0,
+               ("trying to delete a non-empty interface group"));
+
+       ifgroup_lockmgr(LK_EXCLUSIVE);
+       TAILQ_REMOVE(&ifg_head, ifg, ifg_next);
+       ifgroup_lockmgr(LK_RELEASE);
+
+       EVENTHANDLER_INVOKE(group_detach_event, ifg);
+       kfree(ifg, M_IFNET);
+
+       return (0);
+}
+
+/*
+ * Add the interface to a group.
+ * The target group will be created if it doesn't exist.
  */
 int
 if_addgroup(struct ifnet *ifp, const char *groupname)
 {
-       struct ifg_list         *ifgl;
-       struct ifg_group        *ifg = NULL;
-       struct ifg_member       *ifgm;
+       struct ifg_list *ifgl;
+       struct ifg_group *ifg;
+       struct ifg_member *ifgm;
 
-       if (groupname[0] && groupname[strlen(groupname) - 1] >= '0' &&
+       if (groupname[0] &&
+           groupname[strlen(groupname) - 1] >= '0' &&
            groupname[strlen(groupname) - 1] <= '9')
                return (EINVAL);
 
-       TAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next)
-               if (!strcmp(ifgl->ifgl_group->ifg_group, groupname))
-                       return (EEXIST);
-
-       if ((ifgl = kmalloc(sizeof(*ifgl), M_TEMP, M_NOWAIT)) == NULL)
-               return (ENOMEM);
+       ifgroup_lockmgr(LK_SHARED);
 
-       if ((ifgm = kmalloc(sizeof(*ifgm), M_TEMP, M_NOWAIT)) == NULL) {
-               kfree(ifgl, M_TEMP);
-               return (ENOMEM);
+       TAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next) {
+               if (strcmp(ifgl->ifgl_group->ifg_group, groupname) == 0) {
+                       ifgroup_lockmgr(LK_RELEASE);
+                       return (EEXIST);
+               }
        }
 
-       TAILQ_FOREACH(ifg, &ifg_head, ifg_next)
-               if (!strcmp(ifg->ifg_group, groupname))
+       TAILQ_FOREACH(ifg, &ifg_head, ifg_next) {
+               if (strcmp(ifg->ifg_group, groupname) == 0)
                        break;
-
-       if (ifg == NULL && (ifg = if_creategroup(groupname)) == NULL) {
-               kfree(ifgl, M_TEMP);
-               kfree(ifgm, M_TEMP);
-               return (ENOMEM);
        }
 
-       ifg->ifg_refcnt++;
+       ifgroup_lockmgr(LK_RELEASE);
+
+       if (ifg == NULL)
+               ifg = if_creategroup(groupname);
+
+       ifgl = kmalloc(sizeof(*ifgl), M_IFNET, M_WAITOK);
+       ifgm = kmalloc(sizeof(*ifgm), M_IFNET, M_WAITOK);
        ifgl->ifgl_group = ifg;
        ifgm->ifgm_ifp = ifp;
+       ifg->ifg_refcnt++;
 
+       ifgroup_lockmgr(LK_EXCLUSIVE);
        TAILQ_INSERT_TAIL(&ifg->ifg_members, ifgm, ifgm_next);
        TAILQ_INSERT_TAIL(&ifp->if_groups, ifgl, ifgl_next);
+       ifgroup_lockmgr(LK_RELEASE);
 
-#if NPF > 0
-       pfi_group_change(groupname);
-#endif
+       EVENTHANDLER_INVOKE(group_change_event, groupname);
 
        return (0);
 }
 
 /*
- * Remove a group from an interface
+ * Remove the interface from a group.
+ * The group will be destroyed if it becomes empty.
+ *
+ * The 'ifgroup_lock' must be hold exclusively when calling this.
  */
-int
-if_delgroup(struct ifnet *ifp, const char *groupname)
+static int
+if_delgroup_locked(struct ifnet *ifp, const char *groupname)
 {
-       struct ifg_list         *ifgl;
-       struct ifg_member       *ifgm;
+       struct ifg_list *ifgl;
+       struct ifg_member *ifgm;
 
-       TAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next)
-               if (!strcmp(ifgl->ifgl_group->ifg_group, groupname))
+       KKASSERT(lockstatus(&ifgroup_lock, curthread) == LK_EXCLUSIVE);
+
+       TAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next) {
+               if (strcmp(ifgl->ifgl_group->ifg_group, groupname) == 0)
                        break;
+       }
        if (ifgl == NULL)
                return (ENOENT);
 
        TAILQ_REMOVE(&ifp->if_groups, ifgl, ifgl_next);
 
-       TAILQ_FOREACH(ifgm, &ifgl->ifgl_group->ifg_members, ifgm_next)
+       TAILQ_FOREACH(ifgm, &ifgl->ifgl_group->ifg_members, ifgm_next) {
                if (ifgm->ifgm_ifp == ifp)
                        break;
+       }
 
        if (ifgm != NULL) {
                TAILQ_REMOVE(&ifgl->ifgl_group->ifg_members, ifgm, ifgm_next);
-               kfree(ifgm, M_TEMP);
-       }
 
-       if (--ifgl->ifgl_group->ifg_refcnt == 0) {
-               TAILQ_REMOVE(&ifg_head, ifgl->ifgl_group, ifg_next);
-#if NPF > 0
-               pfi_detach_ifgroup(ifgl->ifgl_group);
-#endif
-               kfree(ifgl->ifgl_group, M_TEMP);
+               ifgroup_lockmgr(LK_RELEASE);
+               EVENTHANDLER_INVOKE(group_change_event, groupname);
+               ifgroup_lockmgr(LK_EXCLUSIVE);
+
+               kfree(ifgm, M_IFNET);
+               ifgl->ifgl_group->ifg_refcnt--;
        }
 
-       kfree(ifgl, M_TEMP);
+       if (ifgl->ifgl_group->ifg_refcnt == 0) {
+               ifgroup_lockmgr(LK_RELEASE);
+               if_destroygroup(ifgl->ifgl_group);
+               ifgroup_lockmgr(LK_EXCLUSIVE);
+       }
 
-#if NPF > 0
-       pfi_group_change(groupname);
-#endif
+       kfree(ifgl, M_IFNET);
 
        return (0);
 }
 
+int
+if_delgroup(struct ifnet *ifp, const char *groupname)
+{
+       int error;
+
+       ifgroup_lockmgr(LK_EXCLUSIVE);
+       error = if_delgroup_locked(ifp, groupname);
+       ifgroup_lockmgr(LK_RELEASE);
+
+       return (error);
+}
+
 /*
- * Stores all groups from an interface in memory pointed
- * to by data
+ * Store all the groups that the interface belongs to in memory
+ * pointed to by data.
  */
-int
-if_getgroup(caddr_t data, struct ifnet *ifp)
+static int
+if_getgroups(struct ifgroupreq *ifgr, struct ifnet *ifp)
 {
-       int                      len, error;
-       struct ifg_list         *ifgl;
-       struct ifg_req           ifgrq, *ifgp;
-       struct ifgroupreq       *ifgr = (struct ifgroupreq *)data;
+       struct ifg_list *ifgl;
+       struct ifg_req *ifgrq, *p;
+       int len, error;
+
+       len = 0;
+       ifgroup_lockmgr(LK_SHARED);
+       TAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next)
+               len += sizeof(struct ifg_req);
+       ifgroup_lockmgr(LK_RELEASE);
 
        if (ifgr->ifgr_len == 0) {
-               TAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next)
-                       ifgr->ifgr_len += sizeof(struct ifg_req);
+               /*
+                * Caller is asking how much memory should be allocated in
+                * the next request in order to hold all the groups.
+                */
+               ifgr->ifgr_len = len;
                return (0);
+       } else if (ifgr->ifgr_len != len) {
+               return (EINVAL);
        }
 
-       len = ifgr->ifgr_len;
-       ifgp = ifgr->ifgr_groups;
+       ifgrq = kmalloc(len, M_TEMP, M_INTWAIT | M_NULLOK | M_ZERO);
+       if (ifgrq == NULL)
+               return (ENOMEM);
+
+       ifgroup_lockmgr(LK_SHARED);
+       p = ifgrq;
        TAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next) {
-               if (len < sizeof(ifgrq))
+               if (len < sizeof(struct ifg_req)) {
+                       ifgroup_lockmgr(LK_RELEASE);
                        return (EINVAL);
-               bzero(&ifgrq, sizeof ifgrq);
-               strlcpy(ifgrq.ifgrq_group, ifgl->ifgl_group->ifg_group,
-                   sizeof(ifgrq.ifgrq_group));
-               if ((error = copyout((caddr_t)&ifgrq, (caddr_t)ifgp,
-                   sizeof(struct ifg_req))))
-                       return (error);
-               len -= sizeof(ifgrq);
-               ifgp++;
+               }
+
+               strlcpy(p->ifgrq_group, ifgl->ifgl_group->ifg_group,
+                       sizeof(ifgrq->ifgrq_group));
+               len -= sizeof(struct ifg_req);
+               p++;
        }
+       ifgroup_lockmgr(LK_RELEASE);
+
+       error = copyout(ifgrq, ifgr->ifgr_groups, ifgr->ifgr_len);
+       kfree(ifgrq, M_TEMP);
+       if (error)
+               return (error);
 
        return (0);
 }
 
 /*
- * Stores all members of a group in memory pointed to by data
+ * Store all the members of a group in memory pointed to by data.
  */
-int
-if_getgroupmembers(caddr_t data)
+static int
+if_getgroupmembers(struct ifgroupreq *ifgr)
 {
-       struct ifgroupreq       *ifgr = (struct ifgroupreq *)data;
-       struct ifg_group        *ifg;
-       struct ifg_member       *ifgm;
-       struct ifg_req           ifgrq, *ifgp;
-       int                      len, error;
+       struct ifg_group *ifg;
+       struct ifg_member *ifgm;
+       struct ifg_req *ifgrq, *p;
+       int len, error;
+
+       ifgroup_lockmgr(LK_SHARED);
 
-       TAILQ_FOREACH(ifg, &ifg_head, ifg_next)
-               if (!strcmp(ifg->ifg_group, ifgr->ifgr_name))
+       TAILQ_FOREACH(ifg, &ifg_head, ifg_next) {
+               if (strcmp(ifg->ifg_group, ifgr->ifgr_name) == 0)
                        break;
-       if (ifg == NULL)
+       }
+       if (ifg == NULL) {
+               ifgroup_lockmgr(LK_RELEASE);
                return (ENOENT);
+       }
+
+       len = 0;
+       TAILQ_FOREACH(ifgm, &ifg->ifg_members, ifgm_next)
+               len += sizeof(struct ifg_req);
+
+       ifgroup_lockmgr(LK_RELEASE);
 
        if (ifgr->ifgr_len == 0) {
-               TAILQ_FOREACH(ifgm, &ifg->ifg_members, ifgm_next)
-                       ifgr->ifgr_len += sizeof(ifgrq);
+               ifgr->ifgr_len = len;
                return (0);
+       } else if (ifgr->ifgr_len != len) {
+               return (EINVAL);
        }
 
-       len = ifgr->ifgr_len;
-       ifgp = ifgr->ifgr_groups;
+       ifgrq = kmalloc(len, M_TEMP, M_INTWAIT | M_NULLOK | M_ZERO);
+       if (ifgrq == NULL)
+               return (ENOMEM);
+
+       ifgroup_lockmgr(LK_SHARED);
+       p = ifgrq;
        TAILQ_FOREACH(ifgm, &ifg->ifg_members, ifgm_next) {
-               if (len < sizeof(ifgrq))
+               if (len < sizeof(struct ifg_req)) {
+                       ifgroup_lockmgr(LK_RELEASE);
                        return (EINVAL);
-               bzero(&ifgrq, sizeof ifgrq);
-               strlcpy(ifgrq.ifgrq_member, ifgm->ifgm_ifp->if_xname,
-                   sizeof(ifgrq.ifgrq_member));
-               if ((error = copyout((caddr_t)&ifgrq, (caddr_t)ifgp,
-                   sizeof(struct ifg_req))))
-                       return (error);
-               len -= sizeof(ifgrq);
-               ifgp++;
+               }
+
+               strlcpy(p->ifgrq_member, ifgm->ifgm_ifp->if_xname,
+                       sizeof(p->ifgrq_member));
+               len -= sizeof(struct ifg_req);
+               p++;
        }
+       ifgroup_lockmgr(LK_RELEASE);
+
+       error = copyout(ifgrq, ifgr->ifgr_groups, ifgr->ifgr_len);
+       kfree(ifgrq, M_TEMP);
+       if (error)
+               return (error);
 
        return (0);
 }
@@ -1815,6 +1911,7 @@ int
 ifioctl(struct socket *so, u_long cmd, caddr_t data, struct ucred *cred)
 {
        struct ifnet *ifp;
+       struct ifgroupreq *ifgr;
        struct ifreq *ifr;
        struct ifstat *ifs;
        int error, do_ifup = 0;
@@ -1840,13 +1937,15 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct ucred *cred)
                if ((error = priv_check_cred(cred, PRIV_ROOT, 0)) != 0)
                        return (error);
                return (if_clone_create(ifr->ifr_name, sizeof(ifr->ifr_name),
-                       cmd == SIOCIFCREATE2 ? ifr->ifr_data : NULL));
+                       cmd == SIOCIFCREATE2 ? ifr->ifr_data : NULL));
        case SIOCIFDESTROY:
                if ((error = priv_check_cred(cred, PRIV_ROOT, 0)) != 0)
                        return (error);
                return (if_clone_destroy(ifr->ifr_name));
        case SIOCIFGCLONERS:
                return (if_clone_list((struct if_clonereq *)data));
+       case SIOCGIFGMEMB:
+               return (if_getgroupmembers((struct ifgroupreq *)data));
        default:
                break;
        }
@@ -2114,7 +2213,7 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct ucred *cred)
        case SIOCSIFPHYADDR_IN6:
 #endif
        case SIOCSLIFPHYADDR:
-        case SIOCSIFMEDIA:
+       case SIOCSIFMEDIA:
        case SIOCSIFGENERIC:
                error = priv_check_cred(cred, PRIV_ROOT, 0);
                if (error)
@@ -2157,6 +2256,28 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct ucred *cred)
                EVENTHANDLER_INVOKE(iflladdr_event, ifp);
                break;
 
+       case SIOCAIFGROUP:
+               ifgr = (struct ifgroupreq *)ifr;
+               if ((error = priv_check_cred(cred, PRIV_NET_ADDIFGROUP, 0)))
+                       return (error);
+               if ((error = if_addgroup(ifp, ifgr->ifgr_group)))
+                       return (error);
+               break;
+
+       case SIOCDIFGROUP:
+               ifgr = (struct ifgroupreq *)ifr;
+               if ((error = priv_check_cred(cred, PRIV_NET_DELIFGROUP, 0)))
+                       return (error);
+               if ((error = if_delgroup(ifp, ifgr->ifgr_group)))
+                       return (error);
+               break;
+
+       case SIOCGIFGROUP:
+               ifgr = (struct ifgroupreq *)ifr;
+               if ((error = if_getgroups(ifgr, ifp)))
+                       return (error);
+               break;
+
        default:
                oif_flags = ifp->if_flags;
                if (so->so_proto == 0) {
index 9cf4f12..a5fd574 100644 (file)
@@ -325,8 +325,8 @@ struct      ifconf {
 
 struct ifg_req {
        union {
-               char                     ifgrqu_group[IFNAMSIZ];
-               char                     ifgrqu_member[IFNAMSIZ];
+               char    ifgrqu_group[IFNAMSIZ];
+               char    ifgrqu_member[IFNAMSIZ];
        } ifgrq_ifgrqu;
 #define        ifgrq_group     ifgrq_ifgrqu.ifgrqu_group
 #define        ifgrq_member    ifgrq_ifgrqu.ifgrqu_member
index 2edcd6a..70883c5 100644 (file)
@@ -105,9 +105,14 @@ struct     ifdata_pcpu;
 
 #define IF_DUNIT_NONE   -1
 
-TAILQ_HEAD(ifnethead, ifnet);  /* we use TAILQs so that the order of */
-TAILQ_HEAD(ifaddrhead, ifaddr_container); /* instantiation is preserved in the list */
+/*
+ * we use TAILQs so that the order of instantiation is preserved in
+ * the list.
+ */
+TAILQ_HEAD(ifnethead, ifnet);
+TAILQ_HEAD(ifaddrhead, ifaddr_container);
 TAILQ_HEAD(ifmultihead, ifmultiaddr);
+TAILQ_HEAD(ifgrouphead, ifg_group);
 
 /*
  * Structure defining a mbuf queue.
@@ -330,7 +335,12 @@ struct ifnet {
        struct  if_data if_data;        /* NOTE: stats are in if_data_pcpu */
        struct  ifmultihead if_multiaddrs; /* multicast addresses configured */
        int     if_amcount;             /* number of all-multicast requests */
-/* procedure handles */
+       TAILQ_HEAD(, ifg_list) if_groups; /* linked list of groups per if;
+                                          * protected by 'ifgroup_lock' */
+
+       /*
+        * procedure handlers
+        */
        int     (*if_output)            /* output routine (enqueue) */
                (struct ifnet *, struct mbuf *, struct sockaddr *,
                     struct rtentry *);
@@ -348,7 +358,6 @@ struct ifnet {
        int     (*if_resolvemulti)      /* validate/resolve multicast */
                (struct ifnet *, struct sockaddr **, struct sockaddr *);
        void    *if_unused5;
-       TAILQ_HEAD(, ifg_list) if_groups; /* linked list of groups per if */
        int     (*if_mapsubq)           /* cpuid to if_snd subqueue map */
                (struct ifaltq *, int);
        int     if_unused2;
@@ -723,12 +732,12 @@ struct ifnet_array {
  * interface groups
  */
 struct ifg_group {
-       char                             ifg_group[IFNAMSIZ];
-       u_int                            ifg_refcnt;
-       void                            *ifg_pf_kif;
-       int                              ifg_carp_demoted;
-       TAILQ_HEAD(, ifg_member)         ifg_members;
-       TAILQ_ENTRY(ifg_group)           ifg_next;
+       char                     ifg_group[IFNAMSIZ];
+       u_int                    ifg_refcnt;
+       void                    *ifg_pf_kif;
+       int                      ifg_carp_demoted;
+       TAILQ_HEAD(, ifg_member) ifg_members;
+       TAILQ_ENTRY(ifg_group)   ifg_next;
 };
 
 struct ifg_member {
@@ -889,6 +898,7 @@ int                 ifnet_array_isempty(void);
 
 extern int ifqmaxlen;
 extern struct ifnet *loif;
+extern struct ifgrouphead ifg_head;
 
 struct ip;
 struct tcphdr;
@@ -935,11 +945,9 @@ void       if_up(struct ifnet *);
 int    ifioctl(struct socket *, u_long, caddr_t, struct ucred *);
 int    ifpromisc(struct ifnet *, int);
 
-struct ifg_group *if_creategroup(const char *);
-int     if_addgroup(struct ifnet *, const char *);
-int     if_delgroup(struct ifnet *, const char *);
-int     if_getgroup(caddr_t, struct ifnet *);
-int     if_getgroupmembers(caddr_t);
+int    ifgroup_lockmgr(u_int flags);
+int    if_addgroup(struct ifnet *, const char *);
+int    if_delgroup(struct ifnet *, const char *);
 
 struct ifaddr *ifa_ifwithaddr(struct sockaddr *);
 struct ifaddr *ifa_ifwithdstaddr(struct sockaddr *);
index 8d89e1d..60d94f2 100644 (file)
  * 500313 - remove vmnet support from tap(4) (VMIO_* ioctls)
  * 500314 - add TAPGIFNAME to tap(4)
  * 500315 - add TUNGIFNAME to tun(4)
+ * 500316 - add SIOC[ADG]IFGROUP, SIOCGIFGMEMB ioctl
  */
 #undef __DragonFly_version
-#define __DragonFly_version 500315     /* propagated to newvers */
+#define __DragonFly_version 500316     /* propagated to newvers */
 
 #include <sys/_null.h>
 
index ddb3108..01a766f 100644 (file)
@@ -75,7 +75,7 @@
 /* 36 SIOCGIFCONF */
 /* 37 SIOCGIFNETMASK */
 #define        SIOCGIFDATA     _IOWR('i', 38, struct ifreq)    /* get if_data */
-#define        SIOCSIFNAME     _IOW('i', 40, struct ifreq)     /* set IF name */
+#define        SIOCSIFNAME      _IOW('i', 40, struct ifreq)    /* set IF name */
 
 #define        SIOCADDMULTI     _IOW('i', 49, struct ifreq)    /* add m'cast addr */
 #define        SIOCDELMULTI     _IOW('i', 50, struct ifreq)    /* del m'cast addr */
 #define SIOCSIFTSOLEN   _IOW('i', 127, struct ifreq)   /* set max TSO len */
 #define SIOCGIFTSOLEN  _IOWR('i', 128, struct ifreq)   /* get max TSO len */
 
+#define        SIOCAIFGROUP     _IOW('i', 135, struct ifgroupreq) /* add an ifgroup */
+#define        SIOCGIFGROUP    _IOWR('i', 136, struct ifgroupreq) /* get ifgroups */
+#define        SIOCDIFGROUP     _IOW('i', 137, struct ifgroupreq) /* delete ifgroup */
 #define        SIOCGIFGMEMB    _IOWR('i', 138, struct ifgroupreq) /* get members */
 
 #endif /* !_SYS_SOCKIO_H_ */