summaryrefslogtreecommitdiffstats
path: root/sys/net/bridge.c
diff options
context:
space:
mode:
authorluigi <luigi@FreeBSD.org>2001-11-04 22:56:25 +0000
committerluigi <luigi@FreeBSD.org>2001-11-04 22:56:25 +0000
commitf565e0a1dff9f306dcf2a7ce69991a22170dfa34 (patch)
treec941161cecb4fb744bf3988da945ddfd0a75a240 /sys/net/bridge.c
parent473a686e79edeaa4c5a1b0e1fced3d7dcc9ef444 (diff)
downloadFreeBSD-src-f565e0a1dff9f306dcf2a7ce69991a22170dfa34.zip
FreeBSD-src-f565e0a1dff9f306dcf2a7ce69991a22170dfa34.tar.gz
MFS: sync the ipfw/dummynet/bridge code with the one recently merged
into stable (mostly , but not only, formatting and comments changes).
Diffstat (limited to 'sys/net/bridge.c')
-rw-r--r--sys/net/bridge.c261
1 files changed, 173 insertions, 88 deletions
diff --git a/sys/net/bridge.c b/sys/net/bridge.c
index 5feecbc..abc998a 100644
--- a/sys/net/bridge.c
+++ b/sys/net/bridge.c
@@ -74,12 +74,12 @@
#include <sys/malloc.h>
#include <sys/systm.h>
#include <sys/socket.h> /* for net/if.h */
+#include <sys/ctype.h> /* string functions */
#include <sys/kernel.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_types.h>
-#include <net/if_var.h>
#include <netinet/in.h> /* for struct arpcom */
#include <netinet/in_systm.h>
@@ -87,18 +87,14 @@
#include <netinet/ip.h>
#include <netinet/if_ether.h> /* for struct arpcom */
-#if !defined(KLD_MODULE)
-#include "opt_ipfw.h"
-#include "opt_ipdn.h"
-#endif
-
#include <net/route.h>
#include <netinet/ip_fw.h>
#include <netinet/ip_dummynet.h>
#include <net/bridge.h>
static struct ifnet *bridge_in(struct ifnet *, struct ether_header *);
-static struct mbuf *bdg_forward(struct mbuf *, struct ether_header *const, struct ifnet *);
+static struct mbuf *bdg_forward(struct mbuf *,
+ struct ether_header *const, struct ifnet *);
static void bdgtakeifaces(void);
/*
@@ -116,15 +112,24 @@ static void bdgtakeifaces(void);
#define DDB(x) x
#define DEB(x)
-static void bdginit(void *);
+static int bdginit(void);
static void flush_table(void);
static void bdg_promisc_on(void);
static void parse_bdg_cfg(void);
-static int bdg_initialized = 0;
-
static int bdg_ipfw = 0 ;
-bdg_hash_table *bdg_table = NULL ;
+static bdg_hash_table *bdg_table = NULL ;
+
+static char *bdg_dst_names[] = {
+ "BDG_NULL ",
+ "BDG_BCAST ",
+ "BDG_MCAST ",
+ "BDG_LOCAL ",
+ "BDG_DROP ",
+ "BDG_UNKNOWN ",
+ "BDG_IN ",
+ "BDG_OUT ",
+ "BDG_FORWARD " };
/*
* System initialization
@@ -137,6 +142,45 @@ static struct callout_handle bdg_timeout_h ;
if (ifp2sc[ifp->if_index].magic != 0xDEADBEEF) { x ; }
/*
+ * Find the right pkt destination:
+ * BDG_BCAST is a broadcast
+ * BDG_MCAST is a multicast
+ * BDG_LOCAL is for a local address
+ * BDG_DROP must be dropped
+ * other ifp of the dest. interface (incl.self)
+ *
+ * We assume this is only called for interfaces for which bridging
+ * is enabled, i.e. BDG_USED(ifp) is true.
+ */
+static __inline
+struct ifnet *
+bridge_dst_lookup(struct ether_header *eh)
+{
+ struct ifnet *dst ;
+ int index ;
+ bdg_addr *p ;
+
+ if (IS_ETHER_BROADCAST(eh->ether_dhost))
+ return BDG_BCAST ;
+ if (eh->ether_dhost[0] & 1)
+ return BDG_MCAST ;
+ /*
+ * Lookup local addresses in case one matches.
+ */
+ for (index = bdg_ports, p = bdg_addresses ; index ; index--, p++ )
+ if (BDG_MATCH(p->etheraddr, eh->ether_dhost) )
+ return BDG_LOCAL ;
+ /*
+ * Look for a possible destination in table
+ */
+ index= HASH_FN( eh->ether_dhost );
+ dst = bdg_table[index].name;
+ if ( dst && BDG_MATCH( bdg_table[index].etheraddr, eh->ether_dhost) )
+ return dst ;
+ else
+ return BDG_UNKNOWN ;
+}
+/*
* turn off promisc mode, optionally clear the IFF_USED flag.
* The flag is turned on by parse_bdg_config
*/
@@ -207,8 +251,6 @@ sysctl_bdg(SYSCTL_HANDLER_ARGS)
oidp->oid_name, oidp->oid_arg2,
oldval, do_bridge); )
- if (bdg_table == NULL)
- do_bridge = 0 ;
if (oldval != do_bridge) {
bdg_promisc_off( 1 ); /* reset previously used interfaces */
flush_table();
@@ -225,6 +267,8 @@ static char bridge_cfg[256] = { "" } ;
/*
* parse the config string, set IFF_USED, name and cluster_id
* for all interfaces found.
+ * The config string is a list of "if[:cluster]" with
+ * a number of possible separators (see "sep").
*/
static void
parse_bdg_cfg()
@@ -232,20 +276,21 @@ parse_bdg_cfg()
char *p, *beg ;
int i, l, cluster;
struct bdg_softc *b;
+ static char *sep = ", \t";
- for (p= bridge_cfg; *p ; p++) {
- /* interface names begin with [a-z] and continue up to ':' */
- if (*p < 'a' || *p > 'z')
+ for (p = bridge_cfg; *p ; p++) {
+ if (index(sep, *p)) /* skip separators */
continue ;
- for ( beg = p ; *p && *p != ':' ; p++ )
+ /* names are lowercase and digits */
+ for ( beg = p ; islower(*p) || isdigit(*p) ; p++ )
;
- if (*p == 0) /* end of string, ':' not found */
- return ;
- l = p - beg ; /* length of name string */
- p++ ;
- DEB(printf("-- match beg(%d) <%s> p <%s>\n", l, beg, p);)
- for (cluster = 0 ; *p && *p >= '0' && *p <= '9' ; p++)
- cluster = cluster*10 + (*p -'0');
+ l = p - beg ; /* length of name string */
+ if (l == 0) /* invalid name */
+ break ;
+ if ( *p != ':' ) /* no ':', assume default cluster 1 */
+ cluster = 1 ;
+ else /* fetch cluster */
+ cluster = strtoul( p+1, &p, 10);
/*
* now search in bridge strings
*/
@@ -256,7 +301,7 @@ parse_bdg_cfg()
if (ifp == NULL)
continue;
sprintf(buf, "%s%d", ifp->if_name, ifp->if_unit);
- if (!strncmp(beg, buf, l)) { /* XXX not correct for >10 if! */
+ if (!strncmp(beg, buf, l)) {
b->cluster_id = htons(cluster) ;
b->flags |= IFF_USED ;
sprintf(bdg_stats.s[ifp->if_index].name,
@@ -267,8 +312,6 @@ parse_bdg_cfg()
break ;
}
}
- if (*p == '\0')
- break ;
}
}
@@ -319,6 +362,10 @@ SYSCTL_PROC(_net_link_ether, OID_AUTO, bridge, CTLTYPE_INT|CTLFLAG_RW,
SYSCTL_INT(_net_link_ether, OID_AUTO, bridge_ipfw, CTLFLAG_RW,
&bdg_ipfw,0,"Pass bridged pkts through firewall");
+/*
+ * The follow macro declares a variable, and maps it to
+ * a SYSCTL_INT entry with the same name.
+ */
#define SY(parent, var, comment) \
static int var ; \
SYSCTL_INT(parent, OID_AUTO, var, CTLFLAG_RW, &(var), 0, comment);
@@ -334,6 +381,7 @@ SYSCTL_INT(_net_link_ether, OID_AUTO, bridge_ipfw_collisions,
SYSCTL_PROC(_net_link_ether, OID_AUTO, bridge_refresh, CTLTYPE_INT|CTLFLAG_WR,
NULL, 0, &sysctl_refresh, "I", "iface refresh");
+#if 1 /* diagnostic vars */
SY(_net_link_ether, verbose, "Be verbose");
SY(_net_link_ether, bdg_split_pkts, "Packets split in bdg_forward");
@@ -348,6 +396,7 @@ SY(_net_link_ether, bdg_predict, "Correctly predicted header location");
SY(_net_link_ether, bdg_fw_avg, "Cycle counter avg");
SY(_net_link_ether, bdg_fw_ticks, "Cycle counter item");
SY(_net_link_ether, bdg_fw_count, "Cycle counter count");
+#endif
SYSCTL_STRUCT(_net_link_ether, PF_BDG, bdgstats,
CTLFLAG_RD, &bdg_stats , bdg_stats, "bridge statistics");
@@ -362,8 +411,6 @@ flush_table()
{
int s,i;
- if (bdg_table == NULL)
- return ;
s = splimp();
for (i=0; i< HASH_SIZE; i++)
bdg_table[i].name= NULL; /* clear table */
@@ -411,32 +458,46 @@ bdg_timeout(void *dummy)
* much faster.
*/
bdg_addr bdg_addresses[BDG_MAX_PORTS];
-int bdg_ports ;
+static int bdg_ports ;
+static int bdg_max_ports = BDG_MAX_PORTS ;
/*
* initialization of bridge code. This needs to be done after all
* interfaces have been configured.
*/
-static void
-bdginit(void *dummy)
+static int
+bdginit(void)
{
-
- bdg_initialized++;
+ bdg_table = (struct hash_table *)
+ malloc(HASH_SIZE * sizeof(struct hash_table),
+ M_IFADDR, M_WAITOK | M_ZERO);
if (bdg_table == NULL)
- bdg_table = (struct hash_table *)
- malloc(HASH_SIZE * sizeof(struct hash_table),
- M_IFADDR, M_WAITOK);
- flush_table();
-
+ return ENOMEM;
ifp2sc = malloc(BDG_MAX_PORTS * sizeof(struct bdg_softc),
- M_IFADDR, M_WAITOK | M_ZERO);
+ M_IFADDR, M_WAITOK | M_ZERO );
+ if (ifp2sc == NULL) {
+ free(bdg_table, M_IFADDR);
+ bdg_table = NULL ;
+ return ENOMEM ;
+ }
+
+ bridge_in_ptr = bridge_in;
+ bdg_forward_ptr = bdg_forward;
+ bdgtakeifaces_ptr = bdgtakeifaces;
+
+ flush_table();
bzero(&bdg_stats, sizeof(bdg_stats) );
bdgtakeifaces();
bdg_timeout(0);
do_bridge=0;
+ return 0 ;
}
-
+
+/**
+ * fetch interfaces that can do bridging.
+ * This is re-done every time we attach or detach an interface.
+ */
static void
bdgtakeifaces(void)
{
@@ -445,15 +506,14 @@ bdgtakeifaces(void)
bdg_addr *p = bdg_addresses ;
struct bdg_softc *bp;
- if (!bdg_initialized)
- return;
-
bdg_ports = 0 ;
*bridge_cfg = '\0';
-
- printf("BRIDGE 011004, have %d interfaces\n", if_index);
+ printf("BRIDGE 011031, have %d interfaces\n", if_index);
TAILQ_FOREACH(ifp, &ifnet, if_link)
if (ifp->if_type == IFT_ETHER) { /* ethernet ? */
+ /*
+ * XXX should try to grow the arrays as needed.
+ */
bp = &ifp2sc[ifp->if_index] ;
ac = (struct arpcom *)ifp;
sprintf(bridge_cfg + strlen(bridge_cfg),
@@ -479,11 +539,11 @@ bdgtakeifaces(void)
}
-/*
+/**
* bridge_in() is invoked to perform bridging decision on input packets.
*
* On Input:
- * eh Ethernet header of the incoming packet.
+ * eh Ethernet header of the incoming packet. We only need this.
*
* On Return: destination of packet, one of
* BDG_BCAST broadcast
@@ -517,7 +577,7 @@ bridge_in(struct ifnet *ifp, struct ether_header *eh)
bdg_table[index].name = NULL ;
} else if (old != ifp) {
/*
- * found a loop. Either a machine has moved, or there
+ * Found a loop. Either a machine has moved, or there
* is a misconfiguration/reconfiguration of the network.
* First, do not forward this packet!
* Record the relocation anyways; then, if loops persist,
@@ -548,12 +608,14 @@ bridge_in(struct ifnet *ifp, struct ether_header *eh)
bdg_table[index].name = ifp ;
}
dst = bridge_dst_lookup(eh);
- /* Return values:
+ /*
+ * bridge_dst_lookup can return the following values:
* BDG_BCAST, BDG_MCAST, BDG_LOCAL, BDG_UNKNOWN, BDG_DROP, ifp.
- * For muted interfaces, the first 3 are changed in BDG_LOCAL,
- * and others to BDG_DROP. Also, for incoming packets, ifp is changed
- * to BDG_DROP in case ifp == src . These mods are not necessary
- * for outgoing packets from ether_output().
+ * For muted interfaces, or when we detect a loop, the first 3 are
+ * changed in BDG_LOCAL (we still listen to incoming traffic),
+ * and others to BDG_DROP (no use for the local host).
+ * Also, for incoming packets, ifp is changed to BDG_DROP if ifp == src.
+ * These changes are not necessary for outgoing packets from ether_output().
*/
BDG_STAT(ifp, BDG_IN);
switch ((uintptr_t)dst) {
@@ -574,36 +636,44 @@ bridge_in(struct ifnet *ifp, struct ether_header *eh)
if ( dropit ) {
if (dst == BDG_BCAST || dst == BDG_MCAST || dst == BDG_LOCAL)
- return BDG_LOCAL ;
+ dst = BDG_LOCAL ;
else
- return BDG_DROP ;
+ dst = BDG_DROP ;
} else {
- return (dst == ifp ? BDG_DROP : dst ) ;
+ if (dst == ifp)
+ dst = BDG_DROP;
}
+ DEB(printf("bridge_in %6D ->%6D ty 0x%04x dst %s%d\n",
+ eh->ether_shost, ".",
+ eh->ether_dhost, ".",
+ ntohs(eh->ether_type),
+ (dst <= BDG_FORWARD) ? bdg_dst_names[(int)dst] :
+ dst->if_name,
+ (dst <= BDG_FORWARD) ? 0 : dst->if_unit); )
+
+ return dst ;
}
/*
- * Forward to dst, excluding src port and muted interfaces.
- * If src == NULL, the pkt comes from ether_output, and dst is the real
- * interface the packet is originally sent to. In this case we must forward
- * it to the whole cluster. We never call bdg_forward ether_output on
- * interfaces which are not part of a cluster.
+ * Forward a packet to dst -- which can be a single interface or
+ * an entire cluster. The src port and muted interfaces are excluded.
*
- * The packet is freed if possible (i.e. surely not of interest for
- * the upper layer), otherwise a copy is left for use by the caller
- * (pointer in m0).
+ * If src == NULL, the pkt comes from ether_output, and dst is the real
+ * interface the packet is originally sent to. In this case, we must forward
+ * it to the whole cluster.
+ * We never call bdg_forward from ether_output on interfaces which are
+ * not part of a cluster.
*
- * It would be more efficient to make bdg_forward() always consume
- * the packet, leaving to the caller the task to check if it needs a copy
- * and get one in case. As it is now, bdg_forward() can sometimes make
- * a copy whereas it is not necessary.
+ * If possible (i.e. we can determine that the caller does not need
+ * a copy), the packet is consumed here, and bdg_forward returns NULL.
+ * Otherwise, a pointer to a copy of the packet is returned.
*
- * XXX be careful about eh, it can be a pointer into *m
+ * XXX be careful with eh, it can be a pointer into *m
*/
static struct mbuf *
bdg_forward(struct mbuf *m0, struct ether_header *const eh, struct ifnet *dst)
{
- struct ifnet *src = m0->m_pkthdr.rcvif; /* could be NULL in output */
+ struct ifnet *src = m0->m_pkthdr.rcvif; /* NULL when called by *_output */
struct ifnet *ifp, *last = NULL ;
int shared = bdg_copy ; /* someone else is using the mbuf */
int once = 0; /* loop only once */
@@ -626,7 +696,7 @@ bdg_forward(struct mbuf *m0, struct ether_header *const eh, struct ifnet *dst)
src = m0->m_pkthdr.rcvif;
shared = 0 ; /* For sure this is our own mbuf. */
} else
- bdg_thru++; /* only count once */
+ bdg_thru++; /* count packet, only once */
if (src == NULL) /* packet from ether_output */
dst = bridge_dst_lookup(eh);
@@ -659,7 +729,7 @@ bdg_forward(struct mbuf *m0, struct ether_header *const eh, struct ifnet *dst)
* Additional restrictions may apply e.g. non-IP, short packets,
* and pkts already gone through a pipe.
*/
- if (ip_fw_chk_ptr && bdg_ipfw != 0 && src != NULL) {
+ if (IPFW_LOADED && bdg_ipfw != 0 && src != NULL) {
struct ip *ip ;
int i;
@@ -696,7 +766,7 @@ bdg_forward(struct mbuf *m0, struct ether_header *const eh, struct ifnet *dst)
* The firewall knows this is a bridged packet as the cookie ptr
* is NULL.
*/
- i = (*ip_fw_chk_ptr)(&ip, 0, NULL, NULL /* cookie */, &m0, &rule, NULL);
+ i = ip_fw_chk_ptr(&ip, 0, NULL, NULL /* cookie */, &m0, &rule, NULL);
if ( (i & IP_FW_PORT_DENY_FLAG) || m0 == NULL) /* drop */
return m0 ;
/*
@@ -709,7 +779,7 @@ bdg_forward(struct mbuf *m0, struct ether_header *const eh, struct ifnet *dst)
if (i == 0) /* a PASS rule. */
goto forward ;
- if (do_bridge && ip_dn_io_ptr != NULL && (i & IP_FW_PORT_DYNT_FLAG)) {
+ if (DUMMYNET_LOADED && (i & IP_FW_PORT_DYNT_FLAG)) {
/*
* Pass the pkt to dummynet, which consumes it.
* If shared, make a copy and keep the original.
@@ -734,7 +804,8 @@ bdg_forward(struct mbuf *m0, struct ether_header *const eh, struct ifnet *dst)
bdg_predict++;
} else {
M_PREPEND(m, ETHER_HDR_LEN, M_DONTWAIT);
- if (!m && verbose) printf("M_PREPEND failed\n");
+ if (!m && verbose)
+ printf("M_PREPEND failed\n");
if (m == NULL) /* nope... */
return m0 ;
bcopy(&save_eh, mtod(m, struct ether_header *), ETHER_HDR_LEN);
@@ -792,7 +863,8 @@ forward:
bdg_predict++;
} else {
M_PREPEND(m, ETHER_HDR_LEN, M_DONTWAIT);
- if (!m && verbose) printf("M_PREPEND failed\n");
+ if (!m && verbose)
+ printf("M_PREPEND failed\n");
if (m == NULL)
return m0;
bcopy(&save_eh, mtod(m, struct ether_header *), ETHER_HDR_LEN);
@@ -827,35 +899,48 @@ forward:
return m0 ;
}
+/*
+ * initialization code, both for static and dynamic loading.
+ */
static int
bridge_modevent(module_t mod, int type, void *unused)
{
int s;
+ int err;
- s = splimp();
switch (type) {
case MOD_LOAD:
- bridge_in_ptr = bridge_in;
- bdg_forward_ptr = bdg_forward;
- bdgtakeifaces_ptr = bdgtakeifaces;
- bdginit(NULL);
+ if (BDG_LOADED) {
+ err = EEXIST;
+ break ;
+ }
+ s = splimp();
+ err = bdginit();
+ splx(s);
break;
case MOD_UNLOAD:
+#if !defined(KLD_MODULE)
+ printf("bridge statically compiled, cannot unload\n");
+ err = EINVAL ;
+#else
+ s = splimp();
do_bridge = 0;
bridge_in_ptr = NULL;
bdg_forward_ptr = NULL;
bdgtakeifaces_ptr = NULL;
untimeout(bdg_timeout, NULL, bdg_timeout_h);
- if (bdg_table != NULL)
- free(bdg_table, M_IFADDR);
- if (ifp2sc != NULL)
- free(ifp2sc, M_IFADDR);
+ free(bdg_table, M_IFADDR);
+ bdg_table = NULL ;
+ free(ifp2sc, M_IFADDR);
+ ifp2sc = NULL ;
+ splx(s);
+#endif
break;
default:
+ err = EINVAL ;
break;
}
- splx(s);
- return 0;
+ return err;
}
static moduledata_t bridge_mod = {
OpenPOWER on IntegriCloud