tech-net archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
bridge(4) - feedback local packets into ether_input()
Hi List!
So my goal is to run a DHCP server and client on two virtual interfaces
and get them talking to each other. After the initial idea of
vether/pair was shot down I looked into what bridge(4) could do after
much prompting by our beloved Taylor.
Here is what I am trying to achieve WITHOUT BPF* (it works with BPF):
DHCP Server --- > tap0 --- > bridge0 <---- tap1 <----- DHCP client
Because tap(4) will drop packets if there is nothing using it as a TAP
device (in this scenario we're just treating it as an endpoint) we have
to solve the problem in bridge(4).
Because DHCP is essentially a broadcast operation, I copied the logic
from bridge_broadcast() into bridge_output() (used for originating local
packets) where we send the packet to ether_input() if it's broadcast or
multicast. Because bridge_output has coding for if src_if == dst_if I
reversed the logic on sending it to ether_input (src_if != dst_if) so
that the receiving interface doesn't double up.
The attached patch allows this to work fine.
Comments are welcome, especially if you think it breaks something.
Roy
* OK the DHCP client still requires BPF but that can be fixed once PR
kern/48280 is.
Index: sys/net/if_bridge.c
===================================================================
RCS file: /cvsroot/src/sys/net/if_bridge.c,v
retrieving revision 1.118
diff -p -u -r1.118 if_bridge.c
--- sys/net/if_bridge.c 22 Apr 2016 00:25:42 -0000 1.118
+++ sys/net/if_bridge.c 22 Apr 2016 00:40:35 -0000
@@ -1431,6 +1431,14 @@ bridge_output(struct ifnet *ifp, struct
eh = mtod(m, struct ether_header *);
sc = ifp->if_bridge;
+ if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
+ if (memcmp(etherbroadcastaddr,
+ eh->ether_dhost, ETHER_ADDR_LEN) == 0)
+ m->m_flags |= M_BCAST;
+ else
+ m->m_flags |= M_MCAST;
+ }
+
/*
* If bridge is down, but the original output interface is up,
* go ahead and send out that interface. Otherwise, the packet
@@ -1446,7 +1454,7 @@ bridge_output(struct ifnet *ifp, struct
* If the packet is a multicast, or we don't know a better way to
* get there, send to all interfaces.
*/
- if (ETHER_IS_MULTICAST(eh->ether_dhost))
+ if ((m->m_flags & (M_MCAST | M_BCAST)) != 0)
dst_if = NULL;
else
dst_if = bridge_rtlookup(sc, eh->ether_dhost);
@@ -1483,7 +1491,10 @@ bridge_output(struct ifnet *ifp, struct
}
if (PSLIST_READER_NEXT(bif, struct bridge_iflist,
- bif_next) == NULL) {
+ bif_next) == NULL &&
+ ((m->m_flags & (M_MCAST | M_BCAST)) == 0 ||
+ dst_if == ifp))
+ {
used = true;
mc = m;
} else {
@@ -1501,6 +1512,36 @@ bridge_output(struct ifnet *ifp, struct
#ifndef NET_MPSAFE
splx(s);
#endif
+
+ if ((m->m_flags & (M_MCAST | M_BCAST)) != 0 &&
+ dst_if != ifp)
+ {
+ if (PSLIST_READER_NEXT(bif,
+ struct bridge_iflist, bif_next) == NULL)
+ {
+ used = true;
+ mc = m;
+ } else {
+ mc = m_copym(m, 0, M_COPYALL,
+ M_DONTWAIT);
+ if (mc == NULL) {
+ sc->sc_if.if_oerrors++;
+ goto next;
+ }
+ }
+
+ mc->m_pkthdr.rcvif = dst_if;
+ mc->m_flags &= ~M_PROMISC;
+
+#ifndef NET_MPSAFE
+ s = splnet();
+#endif
+ ether_input(dst_if, mc);
+#ifndef NET_MPSAFE
+ splx(s);
+#endif
+ }
+
next:
BRIDGE_PSZ_RENTER(s);
bridge_release_member(sc, bif, &psref);
Home |
Main Index |
Thread Index |
Old Index