static errno_t vboxNetAdpDarwinDemux(ifnet_t pIface, mbuf_t pMBuf, char *pFrameHeader, protocol_family_t *pProtocolFamily) { PVBOXNETADP pThis = VBOXNETADP_FROM_IFACE(pIface); Assert(pThis); Log2(("vboxNetAdpDarwinDemux: mode=%d\n", pThis->u.s.nTapMode)); if (pThis->u.s.nTapMode & BPF_MODE_INPUT) { Log2(("vboxnetadp: in len=%d\n%.*Rhxd\n", mbuf_len(pMBuf), 14, pFrameHeader)); bpf_tap_in(pIface, DLT_EN10MB, pMBuf, pFrameHeader, ETHER_HDR_LEN); } return ether_demux(pIface, pMBuf, pFrameHeader, pProtocolFamily); }
/* * Process a received Ethernet packet; the packet is in the * mbuf chain m with the ethernet header at the front. */ static void ether_input_internal(struct ifnet *ifp, struct rte_mbuf *m) { struct ether_header *eh; u_short etype; if (m->data_len < ETHER_HDR_LEN) { /* XXX maybe should pullup? */ RTE_LOG(ERR, NET, "discard frame w/o leading ethernet " "header (len %u pkt len %u)\n", m->data_len, m->l2_len); rte_pktmbuf_free(m); return; } ether_demux(ifp, m); }
/** * Input processing task, handles incoming frames */ static void vboxNetFltFreeBSDinput(void *arg, int pending) { PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)arg; struct mbuf *m, *m0; struct ifnet *ifp = pThis->u.s.ifp; unsigned int cSegs = 0; bool fDropIt = false, fActive; PINTNETSG pSG; VBOXCURVNET_SET(ifp->if_vnet); vboxNetFltRetain(pThis, true /* fBusy */); for (;;) { mtx_lock_spin(&pThis->u.s.inq.ifq_mtx); _IF_DEQUEUE(&pThis->u.s.inq, m); mtx_unlock_spin(&pThis->u.s.inq.ifq_mtx); if (m == NULL) break; for (m0 = m; m0 != NULL; m0 = m0->m_next) if (m0->m_len > 0) cSegs++; #ifdef PADD_RUNT_FRAMES_FROM_HOST if (m_length(m, NULL) < 60) cSegs++; #endif /* Create a copy and deliver to the virtual switch */ pSG = RTMemTmpAlloc(RT_OFFSETOF(INTNETSG, aSegs[cSegs])); vboxNetFltFreeBSDMBufToSG(pThis, m, pSG, cSegs, 0); fDropIt = pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, NULL /* pvIf */, pSG, INTNETTRUNKDIR_WIRE); RTMemTmpFree(pSG); if (fDropIt) m_freem(m); else ether_demux(ifp, m); } vboxNetFltRelease(pThis, true /* fBusy */); VBOXCURVNET_RESTORE(); }
/** * Handle data on netgraph hooks. * Frames processing is deferred to a taskqueue because this might * be called with non-sleepable locks held and code paths inside * the virtual switch might sleep. */ static int ng_vboxnetflt_rcvdata(hook_p hook, item_p item) { const node_p node = NG_HOOK_NODE(hook); PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node); struct ifnet *ifp = pThis->u.s.ifp; struct mbuf *m; struct m_tag *mtag; bool fActive; VBOXCURVNET_SET(ifp->if_vnet); fActive = vboxNetFltTryRetainBusyActive(pThis); NGI_GET_M(item, m); NG_FREE_ITEM(item); /* Locate tag to see if processing should be skipped for this frame */ mtag = m_tag_locate(m, MTAG_VBOX, PACKET_TAG_VBOX, NULL); if (mtag != NULL) { m_tag_unlink(m, mtag); m_tag_free(mtag); } /* * Handle incoming hook. This is connected to the * input path of the interface, thus handling incoming frames. */ if (pThis->u.s.input == hook) { if (mtag != NULL || !fActive) { ether_demux(ifp, m); if (fActive) vboxNetFltRelease(pThis, true /*fBusy*/); VBOXCURVNET_RESTORE(); return (0); } mtx_lock_spin(&pThis->u.s.inq.ifq_mtx); _IF_ENQUEUE(&pThis->u.s.inq, m); mtx_unlock_spin(&pThis->u.s.inq.ifq_mtx); taskqueue_enqueue_fast(taskqueue_fast, &pThis->u.s.tskin); } /* * Handle mbufs on the outgoing hook, frames going to the interface */ else if (pThis->u.s.output == hook) { if (mtag != NULL || !fActive) { int rc = ether_output_frame(ifp, m); if (fActive) vboxNetFltRelease(pThis, true /*fBusy*/); VBOXCURVNET_RESTORE(); return rc; } mtx_lock_spin(&pThis->u.s.outq.ifq_mtx); _IF_ENQUEUE(&pThis->u.s.outq, m); mtx_unlock_spin(&pThis->u.s.outq.ifq_mtx); taskqueue_enqueue_fast(taskqueue_fast, &pThis->u.s.tskout); } else { m_freem(m); } if (fActive) vboxNetFltRelease(pThis, true /*fBusy*/); VBOXCURVNET_RESTORE(); return (0); }
/* * forward a chain of packets to the proper destination. * This runs outside the dummynet lock. */ static void dummynet_send(struct mbuf *m) { struct mbuf *n; for (; m != NULL; m = n) { struct ifnet *ifp = NULL; /* gcc 3.4.6 complains */ struct m_tag *tag; int dst; n = m->m_nextpkt; m->m_nextpkt = NULL; tag = m_tag_first(m); if (tag == NULL) { /* should not happen */ dst = DIR_DROP; } else { struct dn_pkt_tag *pkt = dn_tag_get(m); /* extract the dummynet info, rename the tag * to carry reinject info. */ dst = pkt->dn_dir; ifp = pkt->ifp; tag->m_tag_cookie = MTAG_IPFW_RULE; tag->m_tag_id = 0; } switch (dst) { case DIR_OUT: ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL); break ; case DIR_IN : netisr_dispatch(NETISR_IP, m); break; #ifdef INET6 case DIR_IN | PROTO_IPV6: netisr_dispatch(NETISR_IPV6, m); break; case DIR_OUT | PROTO_IPV6: ip6_output(m, NULL, NULL, IPV6_FORWARDING, NULL, NULL, NULL); break; #endif case DIR_FWD | PROTO_IFB: /* DN_TO_IFB_FWD: */ if (bridge_dn_p != NULL) ((*bridge_dn_p)(m, ifp)); else printf("dummynet: if_bridge not loaded\n"); break; case DIR_IN | PROTO_LAYER2: /* DN_TO_ETH_DEMUX: */ /* * The Ethernet code assumes the Ethernet header is * contiguous in the first mbuf header. * Insure this is true. */ if (m->m_len < ETHER_HDR_LEN && (m = m_pullup(m, ETHER_HDR_LEN)) == NULL) { printf("dummynet/ether: pullup failed, " "dropping packet\n"); break; } ether_demux(m->m_pkthdr.rcvif, m); break; case DIR_OUT | PROTO_LAYER2: /* N_TO_ETH_OUT: */ ether_output_frame(ifp, m); break; case DIR_DROP: /* drop the packet after some time */ FREE_PKT(m); break; default: printf("dummynet: bad switch %d!\n", dst); FREE_PKT(m); break; } } }