Changeset View
Standalone View
sys/net/if_bridge.c
Show First 20 Lines • Show All 261 Lines • ▼ Show 20 Lines | struct bridge_softc { | |||||||||
CK_LIST_HEAD(, bridge_rtnode) *sc_rthash; /* our forwarding table */ | CK_LIST_HEAD(, bridge_rtnode) *sc_rthash; /* our forwarding table */ | |||||||||
CK_LIST_HEAD(, bridge_rtnode) sc_rtlist; /* list version of above */ | CK_LIST_HEAD(, bridge_rtnode) sc_rtlist; /* list version of above */ | |||||||||
uint32_t sc_rthash_key; /* key for hash */ | uint32_t sc_rthash_key; /* key for hash */ | |||||||||
CK_LIST_HEAD(, bridge_iflist) sc_spanlist; /* span ports list */ | CK_LIST_HEAD(, bridge_iflist) sc_spanlist; /* span ports list */ | |||||||||
struct bstp_state sc_stp; /* STP state */ | struct bstp_state sc_stp; /* STP state */ | |||||||||
uint32_t sc_brtexceeded; /* # of cache drops */ | uint32_t sc_brtexceeded; /* # of cache drops */ | |||||||||
struct ifnet *sc_ifaddr; /* member mac copied from */ | struct ifnet *sc_ifaddr; /* member mac copied from */ | |||||||||
struct ether_addr sc_defaddr; /* Default MAC address */ | struct ether_addr sc_defaddr; /* Default MAC address */ | |||||||||
if_input_fn_t sc_if_input; /* Saved copy of if_input */ | ||||||||||
struct epoch_context sc_epoch_ctx; | struct epoch_context sc_epoch_ctx; | |||||||||
}; | }; | |||||||||
VNET_DEFINE_STATIC(struct sx, bridge_list_sx); | VNET_DEFINE_STATIC(struct sx, bridge_list_sx); | |||||||||
#define V_bridge_list_sx VNET(bridge_list_sx) | #define V_bridge_list_sx VNET(bridge_list_sx) | |||||||||
static eventhandler_tag bridge_detach_cookie; | static eventhandler_tag bridge_detach_cookie; | |||||||||
int bridge_rtable_prune_period = BRIDGE_RTABLE_PRUNE_PERIOD; | int bridge_rtable_prune_period = BRIDGE_RTABLE_PRUNE_PERIOD; | |||||||||
Show All 15 Lines | ||||||||||
static void bridge_stop(struct ifnet *, int); | static void bridge_stop(struct ifnet *, int); | |||||||||
static int bridge_transmit(struct ifnet *, struct mbuf *); | static int bridge_transmit(struct ifnet *, struct mbuf *); | |||||||||
#ifdef ALTQ | #ifdef ALTQ | |||||||||
static void bridge_altq_start(if_t); | static void bridge_altq_start(if_t); | |||||||||
static int bridge_altq_transmit(if_t, struct mbuf *); | static int bridge_altq_transmit(if_t, struct mbuf *); | |||||||||
#endif | #endif | |||||||||
static void bridge_qflush(struct ifnet *); | static void bridge_qflush(struct ifnet *); | |||||||||
static struct mbuf *bridge_input(struct ifnet *, struct mbuf *); | static struct mbuf *bridge_input(struct ifnet *, struct mbuf *); | |||||||||
static void bridge_inject(struct ifnet *, struct mbuf *); | ||||||||||
static int bridge_output(struct ifnet *, struct mbuf *, struct sockaddr *, | static int bridge_output(struct ifnet *, struct mbuf *, struct sockaddr *, | |||||||||
struct rtentry *); | struct rtentry *); | |||||||||
static int bridge_enqueue(struct bridge_softc *, struct ifnet *, | static int bridge_enqueue(struct bridge_softc *, struct ifnet *, | |||||||||
struct mbuf *); | struct mbuf *); | |||||||||
static void bridge_rtdelete(struct bridge_softc *, struct ifnet *ifp, int); | static void bridge_rtdelete(struct bridge_softc *, struct ifnet *ifp, int); | |||||||||
static void bridge_forward(struct bridge_softc *, struct bridge_iflist *, | static void bridge_forward(struct bridge_softc *, struct bridge_iflist *, | |||||||||
struct mbuf *m); | struct mbuf *m); | |||||||||
▲ Show 20 Lines • Show All 439 Lines • ▼ Show 20 Lines | #endif | |||||||||
bstp_attach(&sc->sc_stp, &bridge_ops); | bstp_attach(&sc->sc_stp, &bridge_ops); | |||||||||
ether_ifattach(ifp, sc->sc_defaddr.octet); | ether_ifattach(ifp, sc->sc_defaddr.octet); | |||||||||
/* Now undo some of the damage... */ | /* Now undo some of the damage... */ | |||||||||
ifp->if_baudrate = 0; | ifp->if_baudrate = 0; | |||||||||
ifp->if_type = IFT_BRIDGE; | ifp->if_type = IFT_BRIDGE; | |||||||||
#ifdef VIMAGE | #ifdef VIMAGE | |||||||||
ifp->if_reassign = bridge_reassign; | ifp->if_reassign = bridge_reassign; | |||||||||
#endif | #endif | |||||||||
sc->sc_if_input = ifp->if_input; | ||||||||||
vmaffione: Maybe clarify that this is assumed to be `ether_input` at this point?
(The whole thing is quite… | ||||||||||
ifp->if_input = bridge_inject; | ||||||||||
/* | ||||||||||
* Allow BRIDGE_INPUT() to pass in packets originating from the bridge | ||||||||||
* itself. This is required for netmap but otherwise has no effect. | ||||||||||
Done Inline Actions
...to make it clear that bridge_input is called on bifp as a result of bridge_inject. vmaffione: ...to make it clear that `bridge_input` is called on `bifp` as a result of `bridge_inject`. | ||||||||||
*/ | ||||||||||
ifp->if_bridge_input = bridge_input; | ||||||||||
BRIDGE_LIST_LOCK(); | BRIDGE_LIST_LOCK(); | |||||||||
LIST_INSERT_HEAD(&V_bridge_list, sc, sc_list); | LIST_INSERT_HEAD(&V_bridge_list, sc, sc_list); | |||||||||
BRIDGE_LIST_UNLOCK(); | BRIDGE_LIST_UNLOCK(); | |||||||||
*ifpp = ifp; | *ifpp = ifp; | |||||||||
return (0); | return (0); | |||||||||
} | } | |||||||||
▲ Show 20 Lines • Show All 1,547 Lines • ▼ Show 20 Lines | bridge_forward(struct bridge_softc *sc, struct bridge_iflist *sbif, | |||||||||
src_if = m->m_pkthdr.rcvif; | src_if = m->m_pkthdr.rcvif; | |||||||||
ifp = sc->sc_ifp; | ifp = sc->sc_ifp; | |||||||||
if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); | if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); | |||||||||
if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); | if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); | |||||||||
vlan = VLANTAGOF(m); | vlan = VLANTAGOF(m); | |||||||||
if ((sbif->bif_flags & IFBIF_STP) && | ||||||||||
sbif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) | ||||||||||
goto drop; | ||||||||||
vmaffioneUnsubmitted Done Inline Actionsthis change looks unrelated... why is that needed here? vmaffione: this change looks unrelated... why is that needed here? | ||||||||||
markjAuthorUnsubmitted Done Inline ActionsIt's an oversight, this is an unrelated change. (The check is redundant.) markj: It's an oversight, this is an unrelated change. (The check is redundant.) | ||||||||||
eh = mtod(m, struct ether_header *); | eh = mtod(m, struct ether_header *); | |||||||||
dst = eh->ether_dhost; | dst = eh->ether_dhost; | |||||||||
/* If the interface is learning, record the address. */ | /* If the interface is learning, record the address. */ | |||||||||
if (sbif->bif_flags & IFBIF_LEARNING) { | if (sbif->bif_flags & IFBIF_LEARNING) { | |||||||||
error = bridge_rtupdate(sc, eh->ether_shost, vlan, | error = bridge_rtupdate(sc, eh->ether_shost, vlan, | |||||||||
sbif, 0, IFBAF_DYNAMIC); | sbif, 0, IFBAF_DYNAMIC); | |||||||||
/* | /* | |||||||||
* If the interface has addresses limits then deny any source | * If the interface has addresses limits then deny any source | |||||||||
* that is not in the cache. | * that is not in the cache. | |||||||||
*/ | */ | |||||||||
if (error && sbif->bif_addrmax) | if (error && sbif->bif_addrmax) | |||||||||
goto drop; | goto drop; | |||||||||
} | } | |||||||||
if ((sbif->bif_flags & IFBIF_STP) != 0 && | if ((sbif->bif_flags & IFBIF_STP) != 0 && | |||||||||
sbif->bif_stp.bp_state == BSTP_IFSTATE_LEARNING) | sbif->bif_stp.bp_state == BSTP_IFSTATE_LEARNING) | |||||||||
goto drop; | goto drop; | |||||||||
#ifdef DEV_NETMAP | ||||||||||
/* | /* | |||||||||
* If the packet wasn't injected by netmap itself, and the netmap | ||||||||||
* application opted into receiving forwarded packets by putting the | ||||||||||
* interface into promiscuous mode, pass it down. | ||||||||||
vmaffioneUnsubmitted Not Done Inline ActionsIs the mention to promiscuous mode a leftover? In any case, if I'm not mistaken within the if clause it should be if_input == freebsd_generic_rx_handler, so that here netmap intercepts forwarded packets. Maybe the comment maybe a little be more clear and explain this? vmaffione: Is the mention to promiscuous mode a leftover?
In any case, if I'm not mistaken within the if… | ||||||||||
markjAuthorUnsubmitted Done Inline ActionsYes, the comment needs to be updated. The check for IFF_NETMAP in the capenable bits is sufficient. Is there some reason to check if_input specifically? markj: Yes, the comment needs to be updated.
The check for IFF_NETMAP in the capenable bits is… | ||||||||||
vmaffioneUnsubmitted Done Inline ActionsNo, no I was not suggesting to add that check. vmaffione: No, no I was not suggesting to add that check.
I was just asking to clarify that in the comment… | ||||||||||
*/ | ||||||||||
if ((m->m_flags & M_BRIDGE_INJECT) == 0 && | ||||||||||
(if_getcapenable(ifp) & IFCAP_NETMAP) != 0) { | ||||||||||
ifp->if_input(ifp, m); | ||||||||||
return; | ||||||||||
} | ||||||||||
m->m_flags &= ~M_BRIDGE_INJECT; | ||||||||||
#endif | ||||||||||
/* | ||||||||||
* At this point, the port either doesn't participate | * At this point, the port either doesn't participate | |||||||||
* in spanning tree or it is in the forwarding state. | * in spanning tree or it is in the forwarding state. | |||||||||
*/ | */ | |||||||||
/* | /* | |||||||||
* If the packet is unicast, destined for someone on | * If the packet is unicast, destined for someone on | |||||||||
* "this" side of the bridge, drop it. | * "this" side of the bridge, drop it. | |||||||||
*/ | */ | |||||||||
▲ Show 20 Lines • Show All 89 Lines • ▼ Show 20 Lines | ||||||||||
* bridge_input: | * bridge_input: | |||||||||
* | * | |||||||||
* Receive input from a member interface. Queue the packet for | * Receive input from a member interface. Queue the packet for | |||||||||
* bridging if it is not for us. | * bridging if it is not for us. | |||||||||
*/ | */ | |||||||||
static struct mbuf * | static struct mbuf * | |||||||||
bridge_input(struct ifnet *ifp, struct mbuf *m) | bridge_input(struct ifnet *ifp, struct mbuf *m) | |||||||||
{ | { | |||||||||
struct bridge_softc *sc = ifp->if_bridge; | struct bridge_softc *sc; | |||||||||
struct bridge_iflist *bif, *bif2; | struct bridge_iflist *bif, *bif2; | |||||||||
struct ifnet *bifp; | struct ifnet *bifp; | |||||||||
struct ether_header *eh; | struct ether_header *eh; | |||||||||
struct mbuf *mc, *mc2; | struct mbuf *mc, *mc2; | |||||||||
uint16_t vlan; | uint16_t vlan; | |||||||||
int error; | int error; | |||||||||
NET_EPOCH_ASSERT(); | NET_EPOCH_ASSERT(); | |||||||||
if ((sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) | eh = mtod(m, struct ether_header *); | |||||||||
return (m); | vlan = VLANTAGOF(m); | |||||||||
sc = ifp->if_bridge; | ||||||||||
if (sc == NULL) { | ||||||||||
/* | ||||||||||
* This packet originated from the bridge itself, so it must | ||||||||||
* have been transmitted by netmap. Derive the "source" | ||||||||||
* interface from the source address and drop the packet if the | ||||||||||
* source address isn't known. | ||||||||||
*/ | ||||||||||
KASSERT((m->m_flags & M_BRIDGE_INJECT) != 0, | ||||||||||
("%s: ifnet %p missing a bridge softc", __func__, ifp)); | ||||||||||
vmaffioneUnsubmitted Done Inline ActionsMaybe avoid pointer leak, and use if_name(ifp)? vmaffione: Maybe avoid pointer leak, and use `if_name(ifp)`? | ||||||||||
sc = if_getsoftc(ifp); | ||||||||||
ifp = bridge_rtlookup(sc, eh->ether_shost, vlan); | ||||||||||
Not Done Inline ActionsDoes this handle the case of local packet? E.g., a packet that is destined to bifp, intercepted by netmap and then reinjected? vmaffione: Does this handle the case of local packet? E.g., a packet that is destined to `bifp`… | ||||||||||
if (ifp == NULL) { | ||||||||||
if_inc_counter(sc->sc_ifp, IFCOUNTER_IERRORS, 1); | ||||||||||
m_freem(m); | ||||||||||
return (NULL); | ||||||||||
} | ||||||||||
m->m_pkthdr.rcvif = ifp; | ||||||||||
vmaffioneUnsubmitted Done Inline ActionsThe rcvif field is a metadata field that is reconstructed here after netmap has intercepted the packet and reinjected it through the host TX ring. Are we sure there are no additional metadata fields that got lost because of netmap interception? vmaffione: The `rcvif` field is a metadata field that is reconstructed here after netmap has intercepted… | ||||||||||
markjAuthorUnsubmitted Done Inline ActionsYes, I believe this is sufficient from looking at bridge_forward(). I'm not sure what else could be reconstructed - there is no way to tell if this is an existing packet that was reinjected by netmap, or if it's a new packet that is being transmitted by the netmap application. markj: Yes, I believe this is sufficient from looking at bridge_forward(). I'm not sure what else… | ||||||||||
} | ||||||||||
bifp = sc->sc_ifp; | bifp = sc->sc_ifp; | |||||||||
vlan = VLANTAGOF(m); | if ((bifp->if_drv_flags & IFF_DRV_RUNNING) == 0) | |||||||||
return (m); | ||||||||||
/* | /* | |||||||||
* Implement support for bridge monitoring. If this flag has been | * Implement support for bridge monitoring. If this flag has been | |||||||||
* set on this interface, discard the packet once we push it through | * set on this interface, discard the packet once we push it through | |||||||||
* the bpf(4) machinery, but before we do, increment the byte and | * the bpf(4) machinery, but before we do, increment the byte and | |||||||||
* packet counters associated with this interface. | * packet counters associated with this interface. | |||||||||
Done Inline ActionsThis might be too early. I think we still want the kernel to handle 802.1D packets, for instance. markj: This might be too early. I think we still want the kernel to handle 802.1D packets, for… | ||||||||||
*/ | */ | |||||||||
if ((bifp->if_flags & IFF_MONITOR) != 0) { | if ((bifp->if_flags & IFF_MONITOR) != 0) { | |||||||||
m->m_pkthdr.rcvif = bifp; | m->m_pkthdr.rcvif = bifp; | |||||||||
ETHER_BPF_MTAP(bifp, m); | ETHER_BPF_MTAP(bifp, m); | |||||||||
if_inc_counter(bifp, IFCOUNTER_IPACKETS, 1); | if_inc_counter(bifp, IFCOUNTER_IPACKETS, 1); | |||||||||
if_inc_counter(bifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); | if_inc_counter(bifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); | |||||||||
m_freem(m); | m_freem(m); | |||||||||
return (NULL); | return (NULL); | |||||||||
} | } | |||||||||
bif = bridge_lookup_member_if(sc, ifp); | bif = bridge_lookup_member_if(sc, ifp); | |||||||||
if (bif == NULL) { | if (bif == NULL) { | |||||||||
return (m); | return (m); | |||||||||
} | } | |||||||||
eh = mtod(m, struct ether_header *); | ||||||||||
bridge_span(sc, m); | bridge_span(sc, m); | |||||||||
if (m->m_flags & (M_BCAST|M_MCAST)) { | if (m->m_flags & (M_BCAST|M_MCAST)) { | |||||||||
/* Tap off 802.1D packets; they do not get forwarded. */ | /* Tap off 802.1D packets; they do not get forwarded. */ | |||||||||
if (memcmp(eh->ether_dhost, bstp_etheraddr, | if (memcmp(eh->ether_dhost, bstp_etheraddr, | |||||||||
ETHER_ADDR_LEN) == 0) { | ETHER_ADDR_LEN) == 0) { | |||||||||
bstp_input(&bif->bif_stp, ifp, m); /* consumes mbuf */ | bstp_input(&bif->bif_stp, ifp, m); /* consumes mbuf */ | |||||||||
return (NULL); | return (NULL); | |||||||||
Show All 28 Lines | if (m->m_flags & (M_BCAST|M_MCAST)) { | |||||||||
mc2 = m_dup(m, M_NOWAIT); | mc2 = m_dup(m, M_NOWAIT); | |||||||||
if (mc2 != NULL) { | if (mc2 != NULL) { | |||||||||
/* Keep the layer3 header aligned */ | /* Keep the layer3 header aligned */ | |||||||||
int i = min(mc2->m_pkthdr.len, max_protohdr); | int i = min(mc2->m_pkthdr.len, max_protohdr); | |||||||||
mc2 = m_copyup(mc2, i, ETHER_ALIGN); | mc2 = m_copyup(mc2, i, ETHER_ALIGN); | |||||||||
} | } | |||||||||
if (mc2 != NULL) { | if (mc2 != NULL) { | |||||||||
mc2->m_pkthdr.rcvif = bifp; | mc2->m_pkthdr.rcvif = bifp; | |||||||||
(*bifp->if_input)(bifp, mc2); | mc2->m_flags &= ~M_BRIDGE_INJECT; | |||||||||
sc->sc_if_input(bifp, mc2); | ||||||||||
Not Done Inline ActionsSo these packets won't be intercepted by netmap. Is this the desired behaviour? vmaffione: So these packets won't be intercepted by netmap. Is this the desired behaviour? | ||||||||||
Done Inline ActionsOnly a copy is passed to netmap, indeed. Probably we should avoid doing this in netmap mode unless the packet has M_BRIDGE_INJECT set. markj: Only a copy is passed to netmap, indeed. Probably we should avoid doing this in netmap mode… | ||||||||||
} | } | |||||||||
/* Return the original packet for local processing. */ | /* Return the original packet for local processing. */ | |||||||||
return (m); | return (m); | |||||||||
} | } | |||||||||
if ((bif->bif_flags & IFBIF_STP) && | if ((bif->bif_flags & IFBIF_STP) && | |||||||||
bif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) { | bif->bif_stp.bp_state == BSTP_IFSTATE_DISCARDING) { | |||||||||
Show All 11 Lines | ||||||||||
#endif | #endif | |||||||||
#ifdef INET6 | #ifdef INET6 | |||||||||
#define PFIL_HOOKED_INET6 PFIL_HOOKED_IN(V_inet6_pfil_head) | #define PFIL_HOOKED_INET6 PFIL_HOOKED_IN(V_inet6_pfil_head) | |||||||||
#else | #else | |||||||||
#define PFIL_HOOKED_INET6 false | #define PFIL_HOOKED_INET6 false | |||||||||
#endif | #endif | |||||||||
#ifdef DEV_NETMAP | ||||||||||
#define GRAB_FOR_NETMAP(ifp, m) do { \ | ||||||||||
if ((if_getcapenable(ifp) & IFCAP_NETMAP) != 0 && \ | ||||||||||
((m)->m_flags & M_BRIDGE_INJECT) == 0) { \ | ||||||||||
(ifp)->if_input(ifp, m); \ | ||||||||||
return (NULL); \ | ||||||||||
} \ | ||||||||||
} while (0) | ||||||||||
#else | ||||||||||
#define GRAB_FOR_NETMAP(ifp, m) | ||||||||||
#endif | ||||||||||
#define GRAB_OUR_PACKETS(iface) \ | #define GRAB_OUR_PACKETS(iface) \ | |||||||||
if ((iface)->if_type == IFT_GIF) \ | if ((iface)->if_type == IFT_GIF) \ | |||||||||
continue; \ | continue; \ | |||||||||
/* It is destined for us. */ \ | /* It is destined for us. */ \ | |||||||||
if (memcmp(IF_LLADDR(iface), eh->ether_dhost, ETHER_ADDR_LEN) == 0 || \ | if (memcmp(IF_LLADDR(iface), eh->ether_dhost, ETHER_ADDR_LEN) == 0 || \ | |||||||||
CARP_CHECK_WE_ARE_DST(iface)) { \ | CARP_CHECK_WE_ARE_DST(iface)) { \ | |||||||||
if (bif->bif_flags & IFBIF_LEARNING) { \ | if (bif->bif_flags & IFBIF_LEARNING) { \ | |||||||||
error = bridge_rtupdate(sc, eh->ether_shost, \ | error = bridge_rtupdate(sc, eh->ether_shost, \ | |||||||||
vlan, bif, 0, IFBAF_DYNAMIC); \ | vlan, bif, 0, IFBAF_DYNAMIC); \ | |||||||||
if (error && bif->bif_addrmax) { \ | if (error && bif->bif_addrmax) { \ | |||||||||
m_freem(m); \ | m_freem(m); \ | |||||||||
return (NULL); \ | return (NULL); \ | |||||||||
} \ | } \ | |||||||||
} \ | } \ | |||||||||
m->m_pkthdr.rcvif = iface; \ | m->m_pkthdr.rcvif = iface; \ | |||||||||
if ((iface) == ifp) { \ | if ((iface) == ifp) { \ | |||||||||
/* Skip bridge processing... src == dest */ \ | /* Skip bridge processing... src == dest */ \ | |||||||||
return (m); \ | return (m); \ | |||||||||
} \ | } \ | |||||||||
/* It's passing over or to the bridge, locally. */ \ | /* It's passing over or to the bridge, locally. */ \ | |||||||||
ETHER_BPF_MTAP(bifp, m); \ | ETHER_BPF_MTAP(bifp, m); \ | |||||||||
if_inc_counter(bifp, IFCOUNTER_IPACKETS, 1); \ | if_inc_counter(bifp, IFCOUNTER_IPACKETS, 1); \ | |||||||||
if_inc_counter(bifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); \ | if_inc_counter(bifp, IFCOUNTER_IBYTES, m->m_pkthdr.len);\ | |||||||||
/* Hand the packet over to netmap if necessary. */ \ | ||||||||||
GRAB_FOR_NETMAP(bifp, m); \ | ||||||||||
/* Filter on the physical interface. */ \ | /* Filter on the physical interface. */ \ | |||||||||
if (V_pfil_local_phys && (PFIL_HOOKED_IN(V_inet_pfil_head) || \ | if (V_pfil_local_phys && (PFIL_HOOKED_IN(V_inet_pfil_head) || \ | |||||||||
PFIL_HOOKED_INET6)) { \ | PFIL_HOOKED_INET6)) { \ | |||||||||
if (bridge_pfil(&m, NULL, ifp, \ | if (bridge_pfil(&m, NULL, ifp, \ | |||||||||
PFIL_IN) != 0 || m == NULL) { \ | PFIL_IN) != 0 || m == NULL) { \ | |||||||||
return (NULL); \ | return (NULL); \ | |||||||||
} \ | } \ | |||||||||
} \ | } \ | |||||||||
Show All 26 Lines | #define GRAB_OUR_PACKETS(iface) \ | |||||||||
/* Now check the all bridge members. */ | /* Now check the all bridge members. */ | |||||||||
CK_LIST_FOREACH(bif2, &sc->sc_iflist, bif_next) { | CK_LIST_FOREACH(bif2, &sc->sc_iflist, bif_next) { | |||||||||
GRAB_OUR_PACKETS(bif2->bif_ifp) | GRAB_OUR_PACKETS(bif2->bif_ifp) | |||||||||
} | } | |||||||||
#undef CARP_CHECK_WE_ARE_DST | #undef CARP_CHECK_WE_ARE_DST | |||||||||
#undef CARP_CHECK_WE_ARE_SRC | #undef CARP_CHECK_WE_ARE_SRC | |||||||||
#undef PFIL_HOOKED_INET6 | #undef PFIL_HOOKED_INET6 | |||||||||
#undef GRAB_FOR_NETMAP | ||||||||||
#undef GRAB_OUR_PACKETS | #undef GRAB_OUR_PACKETS | |||||||||
/* Perform the bridge forwarding function. */ | /* Perform the bridge forwarding function. */ | |||||||||
bridge_forward(sc, bif, m); | bridge_forward(sc, bif, m); | |||||||||
return (NULL); | return (NULL); | |||||||||
} | ||||||||||
/* | ||||||||||
* Inject a packet back into the host ethernet stack. This will generally only | ||||||||||
* be used by netmap when an application writes to the host TX ring. The | ||||||||||
* M_BRIDGE_INJECT flag ensures that the packet is re-routed to the bridge | ||||||||||
* interface after ethernet processing. | ||||||||||
*/ | ||||||||||
static void | ||||||||||
bridge_inject(struct ifnet *ifp, struct mbuf *m) | ||||||||||
{ | ||||||||||
struct bridge_softc *sc; | ||||||||||
#ifdef DEV_NETMAP | ||||||||||
if ((if_getcapenable(ifp) & IFCAP_NETMAP) != 0) { | ||||||||||
KASSERT((m->m_flags & M_BRIDGE_INJECT) == 0, | ||||||||||
("%s: mbuf %p has M_BRIDGE_INJECT set", __func__, m)); | ||||||||||
vmaffioneUnsubmitted Done Inline ActionsMaybe avoid the kernel pointer leak to protect ASLR? vmaffione: Maybe avoid the kernel pointer leak to protect ASLR? | ||||||||||
markjAuthorUnsubmitted Done Inline ActionsThere is no KASLR, so nothing is leaked really. There are many, many ways to leak kernel pointers besides. Also, this is a panic string, so at that point there is nothing to hide. markj: There is no KASLR, so nothing is leaked really. There are many, many ways to leak kernel… | ||||||||||
vmaffioneUnsubmitted Done Inline ActionsThat's right, but it's more informative if we give the ifp name. vmaffione: That's right, but it's more informative if we give the ifp name. | ||||||||||
m->m_flags |= M_BRIDGE_INJECT; | ||||||||||
} | ||||||||||
#endif | ||||||||||
sc = if_getsoftc(ifp); | ||||||||||
sc->sc_if_input(ifp, m); | ||||||||||
} | } | |||||||||
/* | /* | |||||||||
* bridge_broadcast: | * bridge_broadcast: | |||||||||
* | * | |||||||||
* Send a frame to all interfaces that are members of | * Send a frame to all interfaces that are members of | |||||||||
* the bridge, except for the one on which the packet | * the bridge, except for the one on which the packet | |||||||||
* arrived. | * arrived. | |||||||||
▲ Show 20 Lines • Show All 1,151 Lines • Show Last 20 Lines |
Maybe clarify that this is assumed to be ether_input at this point?
(The whole thing is quite convoluted...)