summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--share/man/man4/bridge.418
-rw-r--r--sys/net/if_bridge.c163
-rw-r--r--sys/net/if_bridge.h11
-rw-r--r--sys/sys/sockio.h5
-rw-r--r--usr.sbin/brconfig/brconfig.810
-rw-r--r--usr.sbin/brconfig/brconfig.c55
6 files changed, 139 insertions, 123 deletions
diff --git a/share/man/man4/bridge.4 b/share/man/man4/bridge.4
index 964d1b36705..2eb36c8290f 100644
--- a/share/man/man4/bridge.4
+++ b/share/man/man4/bridge.4
@@ -1,4 +1,4 @@
-.\" $OpenBSD: bridge.4,v 1.3 1999/03/01 16:55:56 jason Exp $
+.\" $OpenBSD: bridge.4,v 1.4 1999/03/05 21:10:58 jason Exp $
.\"
.\" Copyright (c) 1999 Jason L. Wright (jason@thought.net)
.\" All rights reserved.
@@ -157,6 +157,7 @@ struct ifbaconf {
#define ifbac_buf ifbac_ifbacu.ifbacu_buf
#define ifbac_req ifbac_ifbacu.ifbacu_req
};
+.Ed
.It Dv SIOCBRDGSCACHE
.Pq Li "struct ifbcachereq"
Set the maximum address cache size for the bridge named in
@@ -176,6 +177,21 @@ struct ifbcachereq {
.Pq Li "struct ifbcachereq"
Retrieve the maximum size of the address cache for the bridge
.Ar ifbc_name .
+.It Dv SIOCBRDGSTO
+.Pq Li "struct ifbcachetoreq"
+Set the time, in seconds, that addresses which have not been
+seen on the network (transmitted a packet) remain in the cache.
+If the time is set to zero, no aging is performed on the address
+cache. The argument structure is as follows:
+.Bd -literal -offset indent
+struct ifbcachetoreq {
+ char ifbct_name[IFNAMSIZ]; /* bridge */
+ u_int32_t ifbct_time; /* time */
+};
+.Ed
+.It Dv SIOCBRDGGTO
+.Pq Li "struct ifbcachetoreq"
+Retrieve the address cache expiration time (see above).
.El
.Sh ERRORS
If the
diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c
index e1eb0d47fee..10fee3434a2 100644
--- a/sys/net/if_bridge.c
+++ b/sys/net/if_bridge.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_bridge.c,v 1.3 1999/03/01 04:44:44 jason Exp $ */
+/* $OpenBSD: if_bridge.c,v 1.4 1999/03/05 21:10:52 jason Exp $ */
/*
* Copyright (c) 1999 Jason L. Wright (jason@thought.net)
@@ -74,6 +74,13 @@
#define BRIDGE_RTABLE_MAX 100
#endif
+/*
+ * Timeout (in seconds) for entries learned dynamically
+ */
+#ifndef BRIDGE_RTABLE_TIMEOUT
+#define BRIDGE_RTABLE_TIMEOUT 30
+#endif
+
extern int ifqmaxlen;
/*
@@ -100,9 +107,9 @@ struct bridge_rtnode {
*/
struct bridge_softc {
struct ifnet sc_if; /* the interface */
- u_int32_t sc_brtageidx; /* route age index */
u_int32_t sc_brtmax; /* max # addresses */
u_int32_t sc_brtcnt; /* current # addrs */
+ u_int32_t sc_brttimeout; /* current # addrs */
LIST_HEAD(, bridge_iflist) sc_iflist; /* interface list */
LIST_HEAD(bridge_rthead, bridge_rtnode) *sc_rts;/* hash table */
};
@@ -153,6 +160,7 @@ bridgeattach(unused)
for (i = 0; i < NBRIDGE; i++) {
bridgectl[i].sc_brtmax = BRIDGE_RTABLE_MAX;
+ bridgectl[i].sc_brttimeout = BRIDGE_RTABLE_TIMEOUT;
LIST_INIT(&bridgectl[i].sc_iflist);
ifp = &bridgectl[i].sc_if;
sprintf(ifp->if_xname, "bridge%d", i);
@@ -181,61 +189,41 @@ bridge_ioctl(ifp, cmd, data)
struct ifbaconf *baconf = (struct ifbaconf *)data;
struct ifbcachereq *bcachereq = (struct ifbcachereq *)data;
struct ifbifconf *bifconf = (struct ifbifconf *)data;
+ struct ifbcachetoreq *bcacheto = (struct ifbcachetoreq *)data;
int error = 0, s;
struct bridge_iflist *p;
s = splimp();
switch(cmd) {
case SIOCBRDGADD:
- /*
- * Only root can add interfaces.
- */
if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
break;
- /*
- * Get pointer to ifnet structure for the named interface.
- */
ifs = ifunit(req->ifbr_ifsname);
if (ifs == NULL) { /* no such interface */
error = ENOENT;
break;
}
- /*
- * Check to see if this interface is already a member.
- */
if (ifs->if_bridge == (caddr_t)sc) {
error = EEXIST;
break;
}
- /*
- * Make sure it's not a member of another bridge.
- */
if (ifs->if_bridge != NULL) {
error = EBUSY;
break;
}
- /*
- * Make sure it is an ethernet interface.
- */
if (ifs->if_type != IFT_ETHER) {
error = EINVAL;
break;
}
- /*
- * Put interface into promiscuous mode.
- */
error = ifpromisc(ifs, 1);
if (error != 0)
break;
- /*
- * Allocate list entry.
- */
p = (struct bridge_iflist *) malloc(
sizeof(struct bridge_iflist), M_DEVBUF, M_NOWAIT);
if (p == NULL) { /* list alloc failed */
@@ -244,18 +232,11 @@ bridge_ioctl(ifp, cmd, data)
break;
}
- /*
- * Add to interface list, and give the interface a pointer
- * back to us.
- */
p->ifp = ifs;
LIST_INSERT_HEAD(&sc->sc_iflist, p, next);
ifs->if_bridge = (caddr_t)sc;
break;
case SIOCBRDGDEL:
- /*
- * Only root can delete interfaces.
- */
if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
break;
@@ -263,21 +244,10 @@ bridge_ioctl(ifp, cmd, data)
while (p != NULL) {
if (strncmp(p->ifp->if_xname, req->ifbr_ifsname,
sizeof(p->ifp->if_xname)) == 0) {
- /*
- * Remove the pointer back to us.
- */
p->ifp->if_bridge = NULL;
- /*
- * Decrement promisc count
- */
error = ifpromisc(p->ifp, 0);
- /*
- * Finally, remove from list, delete
- * routes from that interface, and reclaim
- * memory.
- */
LIST_REMOVE(p, next);
bridge_rtdelete(sc, p->ifp);
free(p, M_DEVBUF);
@@ -304,9 +274,22 @@ bridge_ioctl(ifp, cmd, data)
bcachereq->ifbc_size = sc->sc_brtmax;
break;
case SIOCBRDGSCACHE:
+ if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
+ break;
sc->sc_brtmax = bcachereq->ifbc_size;
bridge_rttrim(sc);
break;
+ case SIOCBRDGSTO:
+ if ((error = suser(prc->p_ucred, &prc->p_acflag)) != 0)
+ break;
+ sc->sc_brttimeout = bcacheto->ifbct_time;
+ untimeout(bridge_rtage, sc);
+ if (bcacheto->ifbct_time != 0)
+ timeout(bridge_rtage, sc, sc->sc_brttimeout);
+ break;
+ case SIOCBRDGGTO:
+ bcacheto->ifbct_time = sc->sc_brttimeout;
+ break;
case SIOCSIFFLAGS:
if ((ifp->if_flags & IFF_UP) == IFF_UP)
bridge_init(sc);
@@ -378,8 +361,6 @@ bridge_init(sc)
if ((ifp->if_flags & IFF_RUNNING) == IFF_RUNNING)
return;
- sc->sc_brtageidx = 0;
-
s = splhigh();
if (sc->sc_rts == NULL) {
sc->sc_rts = (struct bridge_rthead *)malloc(
@@ -397,7 +378,8 @@ bridge_init(sc)
ifp->if_flags |= IFF_RUNNING;
splx(s);
- timeout(bridge_rtage, sc, 2 * hz);
+ if (sc->sc_brttimeout != 0)
+ timeout(bridge_rtage, sc, sc->sc_brttimeout * hz);
}
/*
@@ -481,15 +463,9 @@ bridge_output(ifp, m, sa, rt)
if (dst_if == NULL || eh->ether_dhost[0] & 1) {
for (p = LIST_FIRST(&sc->sc_iflist); p != NULL;
p = LIST_NEXT(p, next)) {
- /*
- * Make sure interface is running.
- */
if ((p->ifp->if_flags & IFF_RUNNING) == 0)
continue;
- /*
- * Make sure there's room in the queue.
- */
if (IF_QFULL(&p->ifp->if_snd)) {
sc->sc_if.if_oerrors++;
continue;
@@ -514,9 +490,6 @@ bridge_output(ifp, m, sa, rt)
struct ether_header *ceh;
struct ether_addr *csrc;
- /*
- * Pull up ethernet header.
- */
if (mc->m_len < sizeof(*ceh)) {
mc = m_pullup(mc, sizeof(*ceh));
if (mc == NULL)
@@ -528,9 +501,6 @@ bridge_output(ifp, m, sa, rt)
bcopy(cac->ac_enaddr, csrc, ETHER_ADDR_LEN);
}
- /*
- * Update stats, queue the packet, and start it.
- */
sc->sc_if.if_opackets++;
sc->sc_if.if_obytes += m->m_pkthdr.len;
IF_ENQUEUE(&p->ifp->if_snd, mc);
@@ -598,9 +568,6 @@ bridge_input(ifp, eh, m)
s = splimp();
- /*
- * See if we're running.
- */
if ((sc->sc_if.if_flags & IFF_RUNNING) == 0) {
splx(s);
return (m);
@@ -708,18 +675,12 @@ bridge_input(ifp, eh, m)
* If sucessful lookup, forward packet to that interface only.
*/
if (dst_if != NULL) {
- /*
- * Make sure target interface is running.
- */
if ((dst_if->if_flags & IFF_RUNNING) == 0) {
m_freem(m);
splx(s);
return (NULL);
}
- /*
- * Make sure the interface has room in its queue.
- */
if (IF_QFULL(&dst_if->if_snd)) {
sc->sc_if.if_oerrors++;
m_freem(m);
@@ -727,9 +688,6 @@ bridge_input(ifp, eh, m)
return (NULL);
}
- /*
- * Prepend the ethernet header on to the buffer.
- */
M_PREPEND(m, sizeof(*eh), M_DONTWAIT);
if (m == NULL) {
sc->sc_if.if_oerrors++;
@@ -737,15 +695,9 @@ bridge_input(ifp, eh, m)
}
*mtod(m, struct ether_header *) = *eh;
- /*
- * Update statistics.
- */
sc->sc_if.if_opackets++;
sc->sc_if.if_obytes += m->m_pkthdr.len;
- /*
- * Put it in the interface queue and start transmission.
- */
IF_ENQUEUE(&dst_if->if_snd, m);
if ((dst_if->if_flags & IFF_OACTIVE) == 0)
(*dst_if->if_start)(dst_if);
@@ -793,48 +745,30 @@ bridge_broadcast(sc, ifp, eh, m)
if (p->ifp->if_index == ifp->if_index)
continue;
- /*
- * Make sure target interface is actually running.
- */
if ((p->ifp->if_flags & IFF_RUNNING) == 0)
continue;
- /*
- * Make sure the interface has room in its queue.
- */
if (IF_QFULL(&p->ifp->if_snd)) {
sc->sc_if.if_oerrors++;
continue;
}
- /*
- * Make a copy of the packet.
- */
mc = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
if (mc == NULL) {
sc->sc_if.if_oerrors++;
continue;
}
- /*
- * Update statistics
- */
sc->sc_if.if_opackets++;
sc->sc_if.if_obytes += m->m_pkthdr.len;
if ((eh->ether_shost[0] & 1) == 0)
ifp->if_omcasts++;
- /*
- * Put it in interface queue and start transmission.
- */
IF_ENQUEUE(&p->ifp->if_snd, mc);
if ((p->ifp->if_flags & IFF_OACTIVE) == 0)
(*p->ifp->if_start)(p->ifp);
}
- /*
- * Strip header back off
- */
m_adj(m, sizeof(struct ether_header));
return (m);
}
@@ -1069,13 +1003,16 @@ bridge_rttrim(sc)
splx(s);
}
+/*
+ * Perform an aging cycle
+ */
void
bridge_rtage(vsc)
void *vsc;
{
struct bridge_softc *sc = (struct bridge_softc *)vsc;
struct bridge_rtnode *n, *p;
- int s;
+ int s, i;
s = splhigh();
if (sc->sc_rts == NULL) {
@@ -1083,32 +1020,26 @@ bridge_rtage(vsc)
return;
}
- n = LIST_FIRST(&sc->sc_rts[sc->sc_brtageidx]);
- while (n != NULL) {
- if (n->brt_age) {
- n->brt_age = 0;
- n = LIST_NEXT(n, brt_next);
- }
- else {
- p = LIST_NEXT(n, brt_next);
-#if 1
- printf("RTAGE(%s,%x:%x:%x:%x:%x:%x)\n",
- n->brt_if->if_xname,
- n->brt_addr.ether_addr_octet[0],
- n->brt_addr.ether_addr_octet[1],
- n->brt_addr.ether_addr_octet[2],
- n->brt_addr.ether_addr_octet[3],
- n->brt_addr.ether_addr_octet[4],
- n->brt_addr.ether_addr_octet[5]);
-#endif
- LIST_REMOVE(n, brt_next);
- sc->sc_brtcnt--;
- free(n, M_DEVBUF);
- n = p;
+ for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
+ n = LIST_FIRST(&sc->sc_rts[i]);
+ while (n != NULL) {
+ if (n->brt_age) {
+ n->brt_age = 0;
+ n = LIST_NEXT(n, brt_next);
+ }
+ else {
+ p = LIST_NEXT(n, brt_next);
+ LIST_REMOVE(n, brt_next);
+ sc->sc_brtcnt--;
+ free(n, M_DEVBUF);
+ n = p;
+ }
}
}
- sc->sc_brtageidx = (sc->sc_brtageidx + 1) % BRIDGE_RTABLE_SIZE;
splx(s);
+
+ if (sc->sc_brttimeout != 0)
+ timeout(bridge_rtage, sc, sc->sc_brttimeout * hz);
}
/*
diff --git a/sys/net/if_bridge.h b/sys/net/if_bridge.h
index ec873697c1a..164e75e10e3 100644
--- a/sys/net/if_bridge.h
+++ b/sys/net/if_bridge.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_bridge.h,v 1.2 1999/03/01 04:44:44 jason Exp $ */
+/* $OpenBSD: if_bridge.h,v 1.3 1999/03/05 21:10:52 jason Exp $ */
/*
* Copyright (c) 1999 Jason L. Wright (jason@thought.net)
@@ -82,6 +82,15 @@ struct ifbcachereq {
u_int32_t ifbc_size; /* cache size */
};
+/*
+ * Bridge cache timeout get/set
+ */
+struct ifbcachetoreq {
+ char ifbct_name[IFNAMSIZ]; /* bridge ifs name */
+ u_int32_t ifbct_time; /* cache time (sec) */
+};
+
+
#ifdef _KERNEL
struct mbuf * bridge_input __P((struct ifnet *, struct ether_header *,
struct mbuf *));
diff --git a/sys/sys/sockio.h b/sys/sys/sockio.h
index 4b593d3ce7b..3d64bf9cafd 100644
--- a/sys/sys/sockio.h
+++ b/sys/sys/sockio.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sockio.h,v 1.6 1999/03/01 04:44:43 jason Exp $ */
+/* $OpenBSD: sockio.h,v 1.7 1999/03/05 21:10:55 jason Exp $ */
/* $NetBSD: sockio.h,v 1.5 1995/08/23 00:40:47 thorpej Exp $ */
/*-
@@ -89,6 +89,9 @@
#define SIOCBRDGGCACHE _IOWR('i', 65, struct ifbcachereq) /* get cache size */
#define SIOCBRDGIFS _IOWR('i', 66, struct ifbreq) /* get member ifs */
#define SIOCBRDGRTS _IOWR('i', 67, struct ifbaconf) /* get addresses */
+#define SIOCBRDGSADDR _IOWR('i', 68, struct ifbareq) /* set addr flags */
+#define SIOCBRDGSTO _IOWR('i', 69, struct ifbcachetoreq) /* cache timeout */
+#define SIOCBRDGGTO _IOWR('i', 70, struct ifbcachetoreq) /* cache timeout */
#define SIOCSIFMTU _IOW('i', 127, struct ifreq) /* set ifnet mtu */
#define SIOCGIFMTU _IOWR('i', 126, struct ifreq) /* get ifnet mtu */
diff --git a/usr.sbin/brconfig/brconfig.8 b/usr.sbin/brconfig/brconfig.8
index a613afa2bbe..c9201beb536 100644
--- a/usr.sbin/brconfig/brconfig.8
+++ b/usr.sbin/brconfig/brconfig.8
@@ -1,4 +1,4 @@
-.\" $OpenBSD: brconfig.8,v 1.4 1999/03/01 16:01:48 jason Exp $
+.\" $OpenBSD: brconfig.8,v 1.5 1999/03/05 21:10:55 jason Exp $
.\"
.\" Copyright (c) 1999 Jason L. Wright (jason@thought.net)
.\" All rights reserved.
@@ -46,6 +46,7 @@
.Op Ar add interface-name
.Op Ar delete interface-name
.Op Ar maxaddr size
+.Op Ar timeout time
.Op Ar link0
.Op Ar link1
.Op Ar -link0
@@ -97,6 +98,13 @@ Alias for `delete'.
Set the address cache size to
.Cm size .
The default is 100 entries.
+.It Ar timeout time
+Set the timeout, in seconds, for addresses in the cache to
+.Cm time .
+The default is 30 seconds.
+If
+.Cm time
+is set to zero, then entries will never expire.
.It Ar link0
Setting this flag stops all non-IP multicast packets from
being forwarded by the bridge.
diff --git a/usr.sbin/brconfig/brconfig.c b/usr.sbin/brconfig/brconfig.c
index 6c561fa21f4..9f7d5bf5c15 100644
--- a/usr.sbin/brconfig/brconfig.c
+++ b/usr.sbin/brconfig/brconfig.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: brconfig.c,v 1.3 1999/03/01 04:44:44 jason Exp $ */
+/* $OpenBSD: brconfig.c,v 1.4 1999/03/05 21:10:55 jason Exp $ */
/*
* Copyright (c) 1999 Jason L. Wright (jason@thought.net)
@@ -56,6 +56,7 @@ int bridge_clrflag(int, char *, short);
int bridge_list(int, char *, char *);
int bridge_addrs(int, char *, char *);
int bridge_maxaddr(int, char *, char *);
+int bridge_timeout(int, char *, char *);
int bridge_add(int, char *, char *);
int bridge_delete(int, char *, char *);
int bridge_status(int, char *);
@@ -68,6 +69,8 @@ void printb(char *, unsigned short, char *);
"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6NOTRAILERS\7RUNNING\10NOARP\
\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2\20MULTICAST"
+#define IFBABITS "\020\1BLACKHOLE\2STATIC\3DYNAMIC"
+
void
usage() {
fprintf(stderr, "brconfig -a\n");
@@ -175,6 +178,16 @@ main(argc, argv)
if (error)
return (error);
}
+ else if (strcmp("timeout", argv[0]) == 0) {
+ argc--; argv++;
+ if (argc == 0) {
+ warnx("timeout requires an argument");
+ return (EX_USAGE);
+ }
+ error = bridge_timeout(sock, brdg, argv[0]);
+ if (error)
+ return (error);
+ }
else {
warnx("unrecognized option: %s", argv[0]);
return (EX_USAGE);
@@ -347,6 +360,30 @@ bridge_delete(s, brdg, ifn)
}
int
+bridge_timeout(s, brdg, arg)
+ int s;
+ char *brdg, *arg;
+{
+ struct ifbcachetoreq ifbct;
+ u_int32_t newtime;
+ char *endptr;
+
+ newtime = strtoul(arg, &endptr, 0);
+ if (arg[0] == '\0' || endptr[0] != '\0') {
+ printf("invalid arg for timeout: %s\n", arg);
+ return (EX_USAGE);
+ }
+
+ strncpy(ifbct.ifbct_name, brdg, sizeof ifbct.ifbct_name);
+ ifbct.ifbct_time = newtime;
+ if (ioctl(s, SIOCBRDGSTO, (caddr_t)&ifbct) < 0) {
+ warn("ioctl(SIOCBRDGGCACHE)");
+ return (EX_IOERR);
+ }
+ return (0);
+}
+
+int
bridge_maxaddr(s, brdg, arg)
int s;
char *brdg, *arg;
@@ -400,8 +437,12 @@ bridge_addrs(s, brdg, delim)
ifba = ifbac.ifbac_req + i;
bzero(buf, sizeof(buf));
strncpy(buf, ifba->ifba_name, sizeof(ifba->ifba_name));
- printf("%s%s %s %u\n", delim, ether_ntoa(&ifba->ifba_dst),
+ printf("%s%s %s %u ", delim, ether_ntoa(&ifba->ifba_dst),
buf, ifba->ifba_age);
+#if 0
+ printb("flags", ifba->ifba_flags, IFBABITS);
+#endif
+ printf("\n");
}
return (0);
@@ -442,6 +483,7 @@ bridge_status(s, brdg)
{
struct ifreq ifr;
struct ifbcachereq ifbc;
+ struct ifbcachetoreq ifbct;
int err;
strncpy(ifr.ifr_name, brdg, sizeof ifr.ifr_name);
@@ -468,7 +510,14 @@ bridge_status(s, brdg)
return (EX_IOERR);
}
- printf("\tAddresses (max cache: %u):\n", ifbc.ifbc_size);
+ strncpy(ifbct.ifbct_name, brdg, sizeof ifbct.ifbct_name);
+ if (ioctl(s, SIOCBRDGGTO, (caddr_t)&ifbct) < 0) {
+ warn("ioctl(SIOCBRDGGTO)");
+ return (EX_IOERR);
+ }
+
+ printf("\tAddresses (max cache: %u, timeout: %u):\n",
+ ifbc.ifbc_size, ifbct.ifbct_time);
err = bridge_addrs(s, brdg, "\t\t");
return (err);