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)
This commit is contained in:
parent
343ed0a875
commit
0dad3f0e15
@ -26,6 +26,7 @@ SRCS+= ifvlan.c # SIOC[GS]ETVLAN support
|
||||
SRCS+= ifieee80211.c # SIOC[GS]IEEE80211 support
|
||||
|
||||
SRCS+= ifcarp.c # SIOC[GS]VH support
|
||||
SRCS+= ifgroup.c # ...
|
||||
SRCS+= ifpfsync.c # pfsync(4) support
|
||||
|
||||
SRCS+= ifbridge.c # bridge support
|
||||
|
@ -28,7 +28,7 @@
|
||||
.\" From: @(#)ifconfig.8 8.3 (Berkeley) 1/5/94
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd February 27, 2006
|
||||
.Dd April 12, 2006
|
||||
.Dt IFCONFIG 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -71,6 +71,8 @@
|
||||
.Op Fl u
|
||||
.Op Fl v
|
||||
.Op Fl C
|
||||
.Nm
|
||||
.Op Fl g Ar groupname
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
@ -178,6 +180,8 @@ parameter is a string of the form
|
||||
.Dq name unit ,
|
||||
for example,
|
||||
.Dq Li ed0 .
|
||||
.It Ar groupname
|
||||
List the interfaces in the given group.
|
||||
.El
|
||||
.Pp
|
||||
The following parameters may be set with
|
||||
@ -262,6 +266,22 @@ the system will not attempt to
|
||||
transmit messages through that interface.
|
||||
If possible, the interface will be reset to disable reception as well.
|
||||
This action does not automatically disable routes using the interface.
|
||||
.It Cm group Ar group-name
|
||||
Assign the interface to a
|
||||
.Dq group .
|
||||
Any interface can be in multiple groups.
|
||||
.Pp
|
||||
Cloned interfaces are members of their interface family group by default.
|
||||
For example, a PPP interface such as
|
||||
.Em ppp0
|
||||
is a member of the PPP interface family group,
|
||||
.Em ppp .
|
||||
.\" The interface(s) the default route(s) point to are members of the
|
||||
.\" .Em egress
|
||||
.\" interface group.
|
||||
.It Cm -group Ar group-name
|
||||
Remove the interface from the given
|
||||
.Dq group .
|
||||
.It Cm eui64
|
||||
(Inet6 only.)
|
||||
Fill interface index
|
||||
|
186
sbin/ifconfig/ifgroup.c
Normal file
186
sbin/ifconfig/ifgroup.c
Normal file
@ -0,0 +1,186 @@
|
||||
/*-
|
||||
* Copyright (c) 2006 Max Laier. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static const char rcsid[] =
|
||||
"$FreeBSD$";
|
||||
#endif /* not lint */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "ifconfig.h"
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
setifgroup(const char *group_name, int d, int s, const struct afswtch *rafp)
|
||||
{
|
||||
struct ifgroupreq ifgr;
|
||||
|
||||
memset(&ifgr, 0, sizeof(ifgr));
|
||||
strlcpy(ifgr.ifgr_name, name, IFNAMSIZ);
|
||||
|
||||
if (group_name[0] && isdigit(group_name[strlen(group_name) - 1]))
|
||||
errx(1, "setifgroup: group names may not end in a digit");
|
||||
|
||||
if (strlcpy(ifgr.ifgr_group, group_name, IFNAMSIZ) >= IFNAMSIZ)
|
||||
errx(1, "setifgroup: group name too long");
|
||||
if (ioctl(s, SIOCAIFGROUP, (caddr_t)&ifgr) == -1)
|
||||
err(1," SIOCAIFGROUP");
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
unsetifgroup(const char *group_name, int d, int s, const struct afswtch *rafp)
|
||||
{
|
||||
struct ifgroupreq ifgr;
|
||||
|
||||
memset(&ifgr, 0, sizeof(ifgr));
|
||||
strlcpy(ifgr.ifgr_name, name, IFNAMSIZ);
|
||||
|
||||
if (group_name[0] && isdigit(group_name[strlen(group_name) - 1]))
|
||||
errx(1, "unsetifgroup: group names may not end in a digit");
|
||||
|
||||
if (strlcpy(ifgr.ifgr_group, group_name, IFNAMSIZ) >= IFNAMSIZ)
|
||||
errx(1, "unsetifgroup: group name too long");
|
||||
if (ioctl(s, SIOCDIFGROUP, (caddr_t)&ifgr) == -1)
|
||||
err(1, "SIOCDIFGROUP");
|
||||
}
|
||||
|
||||
static void
|
||||
getifgroups(int s)
|
||||
{
|
||||
int len, cnt;
|
||||
struct ifgroupreq ifgr;
|
||||
struct ifg_req *ifg;
|
||||
|
||||
if (!verbose)
|
||||
return;
|
||||
|
||||
memset(&ifgr, 0, sizeof(ifgr));
|
||||
strlcpy(ifgr.ifgr_name, name, IFNAMSIZ);
|
||||
|
||||
if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1) {
|
||||
if (errno == EINVAL || errno == ENOTTY)
|
||||
return;
|
||||
else
|
||||
err(1, "SIOCGIFGROUP");
|
||||
}
|
||||
|
||||
len = ifgr.ifgr_len;
|
||||
ifgr.ifgr_groups =
|
||||
(struct ifg_req *)calloc(len / sizeof(struct ifg_req),
|
||||
sizeof(struct ifg_req));
|
||||
if (ifgr.ifgr_groups == NULL)
|
||||
err(1, "getifgroups");
|
||||
if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1)
|
||||
err(1, "SIOCGIFGROUP");
|
||||
|
||||
cnt = 0;
|
||||
ifg = ifgr.ifgr_groups;
|
||||
for (; ifg && len >= sizeof(struct ifg_req); ifg++) {
|
||||
len -= sizeof(struct ifg_req);
|
||||
if (strcmp(ifg->ifgrq_group, "all")) {
|
||||
if (cnt == 0)
|
||||
printf("\tgroups: ");
|
||||
cnt++;
|
||||
printf("%s ", ifg->ifgrq_group);
|
||||
}
|
||||
}
|
||||
if (cnt)
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void
|
||||
printgroup(char *groupname)
|
||||
{
|
||||
struct ifgroupreq ifgr;
|
||||
struct ifg_req *ifg;
|
||||
int len, cnt = 0;
|
||||
int s;
|
||||
|
||||
s = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (s == -1)
|
||||
err(1, "socket(AF_INET,SOCK_DGRAM)");
|
||||
bzero(&ifgr, sizeof(ifgr));
|
||||
strlcpy(ifgr.ifgr_name, groupname, sizeof(ifgr.ifgr_name));
|
||||
if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) {
|
||||
if (errno == EINVAL || errno == ENOTTY ||
|
||||
errno == ENOENT)
|
||||
exit(0);
|
||||
else
|
||||
err(1, "SIOCGIFGMEMB");
|
||||
}
|
||||
|
||||
len = ifgr.ifgr_len;
|
||||
if ((ifgr.ifgr_groups = calloc(1, len)) == NULL)
|
||||
err(1, "printgroup");
|
||||
if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1)
|
||||
err(1, "SIOCGIFGMEMB");
|
||||
|
||||
for (ifg = ifgr.ifgr_groups; ifg && len >= sizeof(struct ifg_req);
|
||||
ifg++) {
|
||||
len -= sizeof(struct ifg_req);
|
||||
printf("%s\n", ifg->ifgrq_member);
|
||||
cnt++;
|
||||
}
|
||||
free(ifgr.ifgr_groups);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static struct cmd group_cmds[] = {
|
||||
DEF_CMD_ARG("group", setifgroup),
|
||||
DEF_CMD_ARG("-group", unsetifgroup),
|
||||
};
|
||||
static struct afswtch af_group = {
|
||||
.af_name = "af_group",
|
||||
.af_af = AF_UNSPEC,
|
||||
.af_other_status = getifgroups,
|
||||
};
|
||||
static struct option group_gopt = { "g:", "[-g groupname]", printgroup };
|
||||
|
||||
static __constructor void
|
||||
group_ctor(void)
|
||||
{
|
||||
#define N(a) (sizeof(a) / sizeof(a[0]))
|
||||
int i;
|
||||
|
||||
for (i = 0; i < N(group_cmds); i++)
|
||||
cmd_register(&group_cmds[i]);
|
||||
af_register(&af_group);
|
||||
opt_register(&group_gopt);
|
||||
#undef N
|
||||
}
|
247
sys/net/if.c
247
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;
|
||||
@ -714,6 +722,214 @@ if_detach(struct ifnet *ifp)
|
||||
splx(s);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
@ -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);
|
||||
|
31
sys/net/if.h
31
sys/net/if.h
@ -355,6 +355,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
|
||||
*/
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -117,4 +117,9 @@
|
||||
#define SIOCIFDESTROY _IOW('i', 121, struct ifreq) /* destroy clone if */
|
||||
#define SIOCIFGCLONERS _IOWR('i', 120, struct if_clonereq) /* get cloners */
|
||||
|
||||
#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_ */
|
||||
|
Loading…
Reference in New Issue
Block a user