summaryrefslogtreecommitdiffstats
path: root/sys/net
diff options
context:
space:
mode:
authormlaier <mlaier@FreeBSD.org>2006-06-19 22:20:45 +0000
committermlaier <mlaier@FreeBSD.org>2006-06-19 22:20:45 +0000
commitf5cde2819f76cb3f86ff02a0c422b289ce94a096 (patch)
tree1d514a3c44a007d12f9a4007d15e7afe23180bb0 /sys/net
parent5a4834b848117e80b174a1d51aff1cfd5e9c8c2d (diff)
downloadFreeBSD-src-f5cde2819f76cb3f86ff02a0c422b289ce94a096.zip
FreeBSD-src-f5cde2819f76cb3f86ff02a0c422b289ce94a096.tar.gz
Import interface groups from OpenBSD. This allows to group interfaces in
order to - for example - apply firewall rules to a whole group of interfaces. This is required for importing pf from OpenBSD 3.9 Obtained from: OpenBSD (with changes) Discussed on: -net (back in April)
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/if.c247
-rw-r--r--sys/net/if.h31
-rw-r--r--sys/net/if_clone.c6
-rw-r--r--sys/net/if_var.h37
4 files changed, 321 insertions, 0 deletions
diff --git a/sys/net/if.c b/sys/net/if.c
index 8a98fa6..fc8c1cb 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -113,6 +113,8 @@ static int if_rtdel(struct radix_node *, void *);
static int ifhwioctl(u_long, struct ifnet *, caddr_t, struct thread *);
static void if_start_deferred(void *context, int pending);
static void do_link_state_change(void *, int);
+static int if_getgroup(struct ifgroupreq *, struct ifnet *);
+static int if_getgroupmembers(struct ifgroupreq *);
#ifdef INET6
/*
* XXX: declare here to avoid to include many inet6 related files..
@@ -125,6 +127,7 @@ int if_index = 0;
struct ifindex_entry *ifindex_table = NULL;
int ifqmaxlen = IFQ_MAXLEN;
struct ifnethead ifnet; /* depend on static init XXX */
+struct ifgrouphead ifg_head;
struct mtx ifnet_lock;
static if_com_alloc_t *if_com_alloc[256];
static if_com_free_t *if_com_free[256];
@@ -282,6 +285,7 @@ if_init(void *dummy __unused)
IFNET_LOCK_INIT();
TAILQ_INIT(&ifnet);
+ TAILQ_INIT(&ifg_head);
knlist_init(&ifklist, NULL, NULL, NULL, NULL);
if_grow(); /* create initial table */
ifdev_byindex(0) = make_dev(&net_cdevsw, 0,
@@ -441,6 +445,10 @@ if_attach(struct ifnet *ifp)
TAILQ_INIT(&ifp->if_addrhead);
TAILQ_INIT(&ifp->if_prefixhead);
TAILQ_INIT(&ifp->if_multiaddrs);
+ TAILQ_INIT(&ifp->if_groups);
+
+ if_addgroup(ifp, IFG_ALL);
+
knlist_init(&ifp->if_klist, NULL, NULL, NULL, NULL);
getmicrotime(&ifp->if_lastchange);
ifp->if_data.ifi_epoch = time_uptime;
@@ -715,6 +723,214 @@ if_detach(struct ifnet *ifp)
}
/*
+ * 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);
+
+ IFNET_WLOCK();
+ TAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next)
+ if (!strcmp(ifgl->ifgl_group->ifg_group, groupname)) {
+ IFNET_WUNLOCK();
+ return (EEXIST);
+ }
+
+ if ((ifgl = (struct ifg_list *)malloc(sizeof(struct ifg_list), M_TEMP,
+ M_NOWAIT)) == NULL) {
+ IFNET_WUNLOCK();
+ return (ENOMEM);
+ }
+
+ if ((ifgm = (struct ifg_member *)malloc(sizeof(struct ifg_member),
+ M_TEMP, M_NOWAIT)) == NULL) {
+ free(ifgl, M_TEMP);
+ IFNET_WUNLOCK();
+ return (ENOMEM);
+ }
+
+ TAILQ_FOREACH(ifg, &ifg_head, ifg_next)
+ if (!strcmp(ifg->ifg_group, groupname))
+ break;
+
+ if (ifg == NULL) {
+ if ((ifg = (struct ifg_group *)malloc(sizeof(struct ifg_group),
+ M_TEMP, M_NOWAIT)) == NULL) {
+ free(ifgl, M_TEMP);
+ free(ifgm, M_TEMP);
+ IFNET_WUNLOCK();
+ return (ENOMEM);
+ }
+ strlcpy(ifg->ifg_group, groupname, sizeof(ifg->ifg_group));
+ ifg->ifg_refcnt = 0;
+ TAILQ_INIT(&ifg->ifg_members);
+ EVENTHANDLER_INVOKE(group_attach_event, ifg);
+ TAILQ_INSERT_TAIL(&ifg_head, ifg, ifg_next);
+ }
+
+ ifg->ifg_refcnt++;
+ ifgl->ifgl_group = ifg;
+ ifgm->ifgm_ifp = ifp;
+
+ IF_ADDR_LOCK(ifp);
+ TAILQ_INSERT_TAIL(&ifg->ifg_members, ifgm, ifgm_next);
+ TAILQ_INSERT_TAIL(&ifp->if_groups, ifgl, ifgl_next);
+ IF_ADDR_UNLOCK(ifp);
+
+ IFNET_WUNLOCK();
+
+ EVENTHANDLER_INVOKE(group_change_event, groupname);
+
+ 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;
+
+ IFNET_WLOCK();
+ TAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next)
+ if (!strcmp(ifgl->ifgl_group->ifg_group, groupname))
+ break;
+ if (ifgl == NULL) {
+ IFNET_WUNLOCK();
+ return (ENOENT);
+ }
+
+ IF_ADDR_LOCK(ifp);
+ TAILQ_REMOVE(&ifp->if_groups, ifgl, ifgl_next);
+ IF_ADDR_UNLOCK(ifp);
+
+ 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);
+ free(ifgm, M_TEMP);
+ }
+
+ if (--ifgl->ifgl_group->ifg_refcnt == 0) {
+ TAILQ_REMOVE(&ifg_head, ifgl->ifgl_group, ifg_next);
+ EVENTHANDLER_INVOKE(group_detach_event, ifgl->ifgl_group);
+ free(ifgl->ifgl_group, M_TEMP);
+ }
+ IFNET_WUNLOCK();
+
+ free(ifgl, M_TEMP);
+
+ EVENTHANDLER_INVOKE(group_change_event, groupname);
+
+ return (0);
+}
+
+/*
+ * Stores all groups from an interface in memory pointed
+ * to by data
+ */
+static int
+if_getgroup(struct ifgroupreq *data, struct ifnet *ifp)
+{
+ int len, error;
+ struct ifg_list *ifgl;
+ struct ifg_req ifgrq, *ifgp;
+ struct ifgroupreq *ifgr = data;
+
+ if (ifgr->ifgr_len == 0) {
+ IF_ADDR_LOCK(ifp);
+ TAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next)
+ ifgr->ifgr_len += sizeof(struct ifg_req);
+ IF_ADDR_UNLOCK(ifp);
+ return (0);
+ }
+
+ len = ifgr->ifgr_len;
+ ifgp = ifgr->ifgr_groups;
+ /* XXX: wire */
+ IF_ADDR_LOCK(ifp);
+ TAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next) {
+ if (len < sizeof(ifgrq)) {
+ IF_ADDR_UNLOCK(ifp);
+ return (EINVAL);
+ }
+ bzero(&ifgrq, sizeof ifgrq);
+ strlcpy(ifgrq.ifgrq_group, ifgl->ifgl_group->ifg_group,
+ sizeof(ifgrq.ifgrq_group));
+ if ((error = copyout(&ifgrq, ifgp, sizeof(struct ifg_req)))) {
+ IF_ADDR_UNLOCK(ifp);
+ return (error);
+ }
+ len -= sizeof(ifgrq);
+ ifgp++;
+ }
+ IF_ADDR_UNLOCK(ifp);
+
+ return (0);
+}
+
+/*
+ * Stores all members of a group in memory pointed to by data
+ */
+static int
+if_getgroupmembers(struct ifgroupreq *data)
+{
+ struct ifgroupreq *ifgr = data;
+ struct ifg_group *ifg;
+ struct ifg_member *ifgm;
+ struct ifg_req ifgrq, *ifgp;
+ int len, error;
+
+ IFNET_RLOCK();
+ TAILQ_FOREACH(ifg, &ifg_head, ifg_next)
+ if (!strcmp(ifg->ifg_group, ifgr->ifgr_name))
+ break;
+ if (ifg == NULL) {
+ IFNET_RUNLOCK();
+ return (ENOENT);
+ }
+
+ if (ifgr->ifgr_len == 0) {
+ TAILQ_FOREACH(ifgm, &ifg->ifg_members, ifgm_next)
+ ifgr->ifgr_len += sizeof(ifgrq);
+ IFNET_RUNLOCK();
+ return (0);
+ }
+
+ len = ifgr->ifgr_len;
+ ifgp = ifgr->ifgr_groups;
+ TAILQ_FOREACH(ifgm, &ifg->ifg_members, ifgm_next) {
+ if (len < sizeof(ifgrq)) {
+ IFNET_RUNLOCK();
+ return (EINVAL);
+ }
+ bzero(&ifgrq, sizeof ifgrq);
+ strlcpy(ifgrq.ifgrq_member, ifgm->ifgm_ifp->if_xname,
+ sizeof(ifgrq.ifgrq_member));
+ if ((error = copyout(&ifgrq, ifgp, sizeof(struct ifg_req)))) {
+ IFNET_RUNLOCK();
+ return (error);
+ }
+ len -= sizeof(ifgrq);
+ ifgp++;
+ }
+ IFNET_RUNLOCK();
+
+ return (0);
+}
+
+/*
* Delete Routes for a Network Interface
*
* Called for each routing entry via the rnh->rnh_walktree() call above
@@ -1472,6 +1688,35 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
ifr->ifr_addr.sa_data, ifr->ifr_addr.sa_len);
break;
+ case SIOCAIFGROUP:
+ {
+ struct ifgroupreq *ifgr = (struct ifgroupreq *)ifr;
+
+ error = suser(td);
+ if (error)
+ return (error);
+ if ((error = if_addgroup(ifp, ifgr->ifgr_group)))
+ return (error);
+ break;
+ }
+
+ case SIOCGIFGROUP:
+ if ((error = if_getgroup((struct ifgroupreq *)ifr, ifp)))
+ return (error);
+ break;
+
+ case SIOCDIFGROUP:
+ {
+ struct ifgroupreq *ifgr = (struct ifgroupreq *)ifr;
+
+ error = suser(td);
+ if (error)
+ return (error);
+ if ((error = if_delgroup(ifp, ifgr->ifgr_group)))
+ return (error);
+ break;
+ }
+
default:
error = ENOIOCTL;
break;
@@ -1511,6 +1756,8 @@ ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td)
case SIOCIFGCLONERS:
return (if_clone_list((struct if_clonereq *)data));
+ case SIOCGIFGMEMB:
+ return (if_getgroupmembers((struct ifgroupreq *)data));
}
ifp = ifunit(ifr->ifr_name);
diff --git a/sys/net/if.h b/sys/net/if.h
index f669017..1116d4b 100644
--- a/sys/net/if.h
+++ b/sys/net/if.h
@@ -356,6 +356,37 @@ struct ifconf32 {
#endif
/*
+ * interface groups
+ */
+
+#define IFG_ALL "all" /* group contains all interfaces */
+/* XXX: will we implement this? */
+#define IFG_EGRESS "egress" /* if(s) default route(s) point to */
+
+struct ifg_req {
+ union {
+ char ifgrqu_group[IFNAMSIZ];
+ char ifgrqu_member[IFNAMSIZ];
+ } ifgrq_ifgrqu;
+#define ifgrq_group ifgrq_ifgrqu.ifgrqu_group
+#define ifgrq_member ifgrq_ifgrqu.ifgrqu_member
+};
+
+/*
+ * Used to lookup groups for an interface
+ */
+struct ifgroupreq {
+ char ifgr_name[IFNAMSIZ];
+ u_int ifgr_len;
+ union {
+ char ifgru_group[IFNAMSIZ];
+ struct ifg_req *ifgru_groups;
+ } ifgr_ifgru;
+#define ifgr_group ifgr_ifgru.ifgru_group
+#define ifgr_groups ifgr_ifgru.ifgru_groups
+};
+
+/*
* Structure for SIOC[AGD]LIFADDR
*/
struct if_laddrreq {
diff --git a/sys/net/if_clone.c b/sys/net/if_clone.c
index 89d679d..aa2c21a 100644
--- a/sys/net/if_clone.c
+++ b/sys/net/if_clone.c
@@ -158,6 +158,8 @@ if_clone_createif(struct if_clone *ifc, char *name, size_t len)
if (ifp == NULL)
panic("%s: lookup failed for %s", __func__, name);
+ if_addgroup(ifp, ifc->ifc_name);
+
IF_CLONE_LOCK(ifc);
IFC_IFLIST_INSERT(ifc, ifp);
IF_CLONE_UNLOCK(ifc);
@@ -210,9 +212,13 @@ if_clone_destroyif(struct if_clone *ifc, struct ifnet *ifp)
IFC_IFLIST_REMOVE(ifc, ifp);
IF_CLONE_UNLOCK(ifc);
+ if_delgroup(ifp, ifc->ifc_name);
+
err = (*ifc->ifc_destroy)(ifc, ifp);
if (err != 0) {
+ if_addgroup(ifp, ifc->ifc_name);
+
IF_CLONE_LOCK(ifc);
IFC_IFLIST_INSERT(ifc, ifp);
IF_CLONE_UNLOCK(ifc);
diff --git a/sys/net/if_var.h b/sys/net/if_var.h
index b76e075..84ac364 100644
--- a/sys/net/if_var.h
+++ b/sys/net/if_var.h
@@ -91,6 +91,7 @@ TAILQ_HEAD(ifnethead, ifnet); /* we use TAILQs so that the order of */
TAILQ_HEAD(ifaddrhead, ifaddr); /* instantiation is preserved in the list */
TAILQ_HEAD(ifprefixhead, ifprefix);
TAILQ_HEAD(ifmultihead, ifmultiaddr);
+TAILQ_HEAD(ifgrouphead, ifg_group);
/*
* Structure defining a queue for a network interface.
@@ -182,6 +183,9 @@ struct ifnet {
struct task if_linktask; /* task for link change events */
struct mtx if_addr_mtx; /* mutex to protect address lists */
LIST_ENTRY(ifnet) if_clones; /* interfaces of a cloner */
+ TAILQ_HEAD(, ifg_list) if_groups; /* linked list of groups per if */
+ /* protected by if_addr_mtx */
+ void *if_pf_kif;
};
typedef void if_init_f_t(void *);
@@ -318,6 +322,37 @@ EVENTHANDLER_DECLARE(ifnet_arrival_event, ifnet_arrival_event_handler_t);
typedef void (*ifnet_departure_event_handler_t)(void *, struct ifnet *);
EVENTHANDLER_DECLARE(ifnet_departure_event, ifnet_departure_event_handler_t);
+/*
+ * interface groups
+ */
+struct ifg_group {
+ char ifg_group[IFNAMSIZ];
+ u_int ifg_refcnt;
+ void *ifg_pf_kif;
+ TAILQ_HEAD(, ifg_member) ifg_members;
+ TAILQ_ENTRY(ifg_group) ifg_next;
+};
+
+struct ifg_member {
+ TAILQ_ENTRY(ifg_member) ifgm_next;
+ struct ifnet *ifgm_ifp;
+};
+
+struct ifg_list {
+ struct ifg_group *ifgl_group;
+ TAILQ_ENTRY(ifg_list) ifgl_next;
+};
+
+/* group attach event */
+typedef void (*group_attach_event_handler_t)(void *, struct ifg_group *);
+EVENTHANDLER_DECLARE(group_attach_event, group_attach_event_handler_t);
+/* group detach event */
+typedef void (*group_detach_event_handler_t)(void *, struct ifg_group *);
+EVENTHANDLER_DECLARE(group_detach_event, group_detach_event_handler_t);
+/* group change event */
+typedef void (*group_change_event_handler_t)(void *, const char *);
+EVENTHANDLER_DECLARE(group_change_event, group_change_event_handler_t);
+
#define IF_AFDATA_LOCK_INIT(ifp) \
mtx_init(&(ifp)->if_afdata_mtx, "if_afdata", NULL, MTX_DEF)
#define IF_AFDATA_LOCK(ifp) mtx_lock(&(ifp)->if_afdata_mtx)
@@ -624,6 +659,8 @@ extern int ifqmaxlen;
extern struct ifnet *loif; /* first loopback interface */
extern int if_index;
+int if_addgroup(struct ifnet *, const char *);
+int if_delgroup(struct ifnet *, const char *);
int if_addmulti(struct ifnet *, struct sockaddr *, struct ifmultiaddr **);
int if_allmulti(struct ifnet *, int);
struct ifnet* if_alloc(u_char);
OpenPOWER on IntegriCloud