sys/net: add more interface groups related functions
authorJan Lentfer <Jan.Lentfer@web.de>
Mon, 9 Aug 2010 19:50:20 +0000 (21:50 +0200)
committerJan Lentfer <Jan.Lentfer@web.de>
Mon, 9 Aug 2010 19:53:48 +0000 (21:53 +0200)
if_creategroup()
if_addgroup()
if_delgroup()
if_getgroup()
if_getgroupmembers()

Imported from OpenBSD

sys/net/if.c
sys/net/if_var.h

index 5a43dac..e136420 100644 (file)
@@ -203,6 +203,8 @@ KTR_INFO(KTR_IF_START, if_start, chase_sched, 4,
 #endif
 #define logifstart(name, arg)  KTR_LOG(if_start_ ## name, arg)
 
+TAILQ_HEAD(, ifg_group) ifg_head;
+
 /*
  * Network interface utility routines.
  *
@@ -811,6 +813,201 @@ if_detach(struct ifnet *ifp)
 }
 
 /*
+ * Create interface group without members
+ */
+struct ifg_group *
+if_creategroup(const char *groupname)
+{
+        struct ifg_group        *ifg = NULL;
+
+        if ((ifg = (struct ifg_group *)kmalloc(sizeof(struct ifg_group),
+            M_TEMP, M_NOWAIT)) == NULL)
+                return (NULL);
+
+        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);
+
+        return (ifg);
+}
+
+/*
+ * Add a group to an interface
+ */
+int
+if_addgroup(struct ifnet *ifp, const char *groupname)
+{
+       struct ifg_list         *ifgl;
+       struct ifg_group        *ifg = NULL;
+       struct ifg_member       *ifgm;
+
+       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);
+
+       if ((ifgm = kmalloc(sizeof(*ifgm), M_TEMP, M_NOWAIT)) == NULL) {
+               kfree(ifgl, M_TEMP);
+               return (ENOMEM);
+       }
+
+       TAILQ_FOREACH(ifg, &ifg_head, ifg_next)
+               if (!strcmp(ifg->ifg_group, groupname))
+                       break;
+
+       if (ifg == NULL && (ifg = if_creategroup(groupname)) == NULL) {
+               kfree(ifgl, M_TEMP);
+               kfree(ifgm, M_TEMP);
+               return (ENOMEM);
+       }
+
+       ifg->ifg_refcnt++;
+       ifgl->ifgl_group = ifg;
+       ifgm->ifgm_ifp = ifp;
+
+       TAILQ_INSERT_TAIL(&ifg->ifg_members, ifgm, ifgm_next);
+       TAILQ_INSERT_TAIL(&ifp->if_groups, ifgl, ifgl_next);
+
+#if NPF > 0
+       pfi_group_change(groupname);
+#endif
+
+       return (0);
+}
+
+/*
+ * Remove a group from an interface
+ */
+int
+if_delgroup(struct ifnet *ifp, const char *groupname)
+{
+       struct ifg_list         *ifgl;
+       struct ifg_member       *ifgm;
+
+       TAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next)
+               if (!strcmp(ifgl->ifgl_group->ifg_group, groupname))
+                       break;
+       if (ifgl == NULL)
+               return (ENOENT);
+
+       TAILQ_REMOVE(&ifp->if_groups, ifgl, ifgl_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);
+       }
+
+       kfree(ifgl, M_TEMP);
+
+#if NPF > 0
+       pfi_group_change(groupname);
+#endif
+
+       return (0);
+}
+
+/*
+ * Stores all groups from an interface in memory pointed
+ * to by data
+ */
+int
+if_getgroup(caddr_t data, struct ifnet *ifp)
+{
+       int                      len, error;
+       struct ifg_list         *ifgl;
+       struct ifg_req           ifgrq, *ifgp;
+       struct ifgroupreq       *ifgr = (struct ifgroupreq *)data;
+
+       if (ifgr->ifgr_len == 0) {
+               TAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next)
+                       ifgr->ifgr_len += sizeof(struct ifg_req);
+               return (0);
+       }
+
+       len = ifgr->ifgr_len;
+       ifgp = ifgr->ifgr_groups;
+       TAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next) {
+               if (len < sizeof(ifgrq))
+                       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++;
+       }
+
+       return (0);
+}
+
+/*
+ * Stores all members of a group in memory pointed to by data
+ */
+int
+if_getgroupmembers(caddr_t data)
+{
+       struct ifgroupreq       *ifgr = (struct ifgroupreq *)data;
+       struct ifg_group        *ifg;
+       struct ifg_member       *ifgm;
+       struct ifg_req           ifgrq, *ifgp;
+       int                      len, error;
+
+       TAILQ_FOREACH(ifg, &ifg_head, ifg_next)
+               if (!strcmp(ifg->ifg_group, ifgr->ifgr_name))
+                       break;
+       if (ifg == NULL)
+               return (ENOENT);
+
+       if (ifgr->ifgr_len == 0) {
+               TAILQ_FOREACH(ifgm, &ifg->ifg_members, ifgm_next)
+                       ifgr->ifgr_len += sizeof(ifgrq);
+               return (0);
+       }
+
+       len = ifgr->ifgr_len;
+       ifgp = ifgr->ifgr_groups;
+       TAILQ_FOREACH(ifgm, &ifg->ifg_members, ifgm_next) {
+               if (len < sizeof(ifgrq))
+                       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++;
+       }
+
+       return (0);
+}
+
+/*
  * Delete Routes for a Network Interface
  *
  * Called for each routing entry via the rnh->rnh_walktree() call above
index c016aa8..5bcff90 100644 (file)
@@ -609,6 +609,7 @@ 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;
 };
@@ -756,6 +757,12 @@ int        ifpromisc(struct ifnet *, int);
 struct ifnet *ifunit(const char *);
 struct ifnet *if_withname(struct sockaddr *);
 
+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);
+
 struct ifaddr *ifa_ifwithaddr(struct sockaddr *);
 struct ifaddr *ifa_ifwithdstaddr(struct sockaddr *);
 struct ifaddr *ifa_ifwithnet(struct sockaddr *);