diff options
author | luigi <luigi@FreeBSD.org> | 2001-11-04 22:56:25 +0000 |
---|---|---|
committer | luigi <luigi@FreeBSD.org> | 2001-11-04 22:56:25 +0000 |
commit | f565e0a1dff9f306dcf2a7ce69991a22170dfa34 (patch) | |
tree | c941161cecb4fb744bf3988da945ddfd0a75a240 /sys/net/bridge.c | |
parent | 473a686e79edeaa4c5a1b0e1fced3d7dcc9ef444 (diff) | |
download | FreeBSD-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.c | 261 |
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 = { |