Check the destination ethernet address when not in promiscous mode.
Fix problem where packets would be duplicated, possibly looping, when a domU is doing IP routing. Problem reported and fix tested by Mike M. Volokhov on port-xen While there, add some __predict_false/true in conditionnals where appropriate, remove a always-true test, and fix handling of mbuf shortage.
This commit is contained in:
parent
1edbda9a2e
commit
86110231a4
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: if_xennet.c,v 1.41 2006/01/26 19:17:25 bouyer Exp $ */
|
||||
/* $NetBSD: if_xennet.c,v 1.42 2006/02/01 19:12:02 bouyer Exp $ */
|
||||
|
||||
/*
|
||||
*
|
||||
|
@ -33,7 +33,7 @@
|
|||
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: if_xennet.c,v 1.41 2006/01/26 19:17:25 bouyer Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: if_xennet.c,v 1.42 2006/02/01 19:12:02 bouyer Exp $");
|
||||
|
||||
#include "opt_inet.h"
|
||||
#include "opt_nfs_boot.h"
|
||||
|
@ -691,6 +691,7 @@ xen_network_handler(void *arg)
|
|||
mmu_update_t *mmu = rx_mmu;
|
||||
multicall_entry_t *mcl = rx_mcl;
|
||||
struct mbuf *m;
|
||||
void *pktp;
|
||||
|
||||
xennet_start(ifp); /* to cleanup TX bufs and keep the ifq_send going */
|
||||
|
||||
|
@ -711,7 +712,7 @@ xen_network_handler(void *arg)
|
|||
/* XXXcl check rx->status for error */
|
||||
|
||||
MGETHDR(m, M_DONTWAIT, MT_DATA);
|
||||
if (m == NULL) {
|
||||
if (__predict_false(m == NULL)) {
|
||||
printf("xennet: rx no mbuf\n");
|
||||
ifp->if_ierrors++;
|
||||
break;
|
||||
|
@ -739,14 +740,12 @@ xen_network_handler(void *arg)
|
|||
|
||||
/* Do all the remapping work, and M->P updates, in one
|
||||
* big hypercall. */
|
||||
if ((mcl - rx_mcl) != 0) {
|
||||
mcl->op = __HYPERVISOR_mmu_update;
|
||||
mcl->args[0] = (unsigned long)rx_mmu;
|
||||
mcl->args[1] = mmu - rx_mmu;
|
||||
mcl->args[2] = 0;
|
||||
mcl++;
|
||||
(void)HYPERVISOR_multicall(rx_mcl, mcl - rx_mcl);
|
||||
}
|
||||
if (0)
|
||||
printf("page mapped at va %08lx -> %08x/%08lx\n",
|
||||
sc->sc_rx_bufa[rx->id].xb_rx.xbrx_va,
|
||||
|
@ -763,11 +762,23 @@ xen_network_handler(void *arg)
|
|||
(void *)(PTE_BASE[x86_btop
|
||||
(sc->sc_rx_bufa[rx->id].xb_rx.xbrx_va)] & PG_FRAME)));
|
||||
|
||||
pktp = (void *)(sc->sc_rx_bufa[rx->id].xb_rx.xbrx_va +
|
||||
(rx->addr & PAGE_MASK));
|
||||
if ((ifp->if_flags & IFF_PROMISC) == 0) {
|
||||
struct ether_header *eh = pktp;
|
||||
if (ETHER_IS_MULTICAST(eh->ether_dhost) == 0 &&
|
||||
memcmp(LLADDR(ifp->if_sadl), eh->ether_dhost,
|
||||
ETHER_ADDR_LEN) != 0) {
|
||||
xennet_rx_push_buffer(sc, rx->id);
|
||||
m_freem(m);
|
||||
continue; /* packet not for us */
|
||||
}
|
||||
}
|
||||
m->m_pkthdr.rcvif = ifp;
|
||||
if (sc->sc_rx->req_prod != sc->sc_rx->resp_prod) {
|
||||
if (__predict_true(
|
||||
sc->sc_rx->req_prod != sc->sc_rx->resp_prod)) {
|
||||
m->m_len = m->m_pkthdr.len = rx->status;
|
||||
MEXTADD(m, (void *)(sc->sc_rx_bufa[rx->id].xb_rx.
|
||||
xbrx_va + (rx->addr & PAGE_MASK)), rx->status,
|
||||
MEXTADD(m, pktp, rx->status,
|
||||
M_DEVBUF, xennet_rx_mbuf_free,
|
||||
&sc->sc_rx_bufa[rx->id]);
|
||||
} else {
|
||||
|
@ -778,14 +789,13 @@ xen_network_handler(void *arg)
|
|||
*/
|
||||
m->m_len = MHLEN;
|
||||
m->m_pkthdr.len = 0;
|
||||
m_copyback(m, 0, rx->status,
|
||||
(caddr_t)(sc->sc_rx_bufa[rx->id].xb_rx.xbrx_va +
|
||||
(rx->addr & PAGE_MASK)));
|
||||
m_copyback(m, 0, rx->status, pktp);
|
||||
xennet_rx_push_buffer(sc, rx->id);
|
||||
if (m->m_pkthdr.len < rx->status) {
|
||||
/* out of memory, just drop packets */
|
||||
ifp->if_ierrors++;
|
||||
m_freem(m);
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: xennetback.c,v 1.19 2006/01/23 20:19:08 yamt Exp $ */
|
||||
/* $NetBSD: xennetback.c,v 1.20 2006/02/01 19:12:02 bouyer Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2005 Manuel Bouyer.
|
||||
|
@ -568,8 +568,8 @@ again:
|
|||
txreq =
|
||||
&xneti->xni_txring->ring[MASK_NETIF_TX_IDX(req_cons)].req;
|
||||
XENPRINTF(("%s pkt size %d\n", xneti->xni_if.if_xname, txreq->size));
|
||||
if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) !=
|
||||
(IFF_UP | IFF_RUNNING)) {
|
||||
if (__predict_false((ifp->if_flags & (IFF_UP | IFF_RUNNING)) !=
|
||||
(IFF_UP | IFF_RUNNING))) {
|
||||
/* interface not up, drop */
|
||||
xennetback_tx_response(xneti, txreq->id,
|
||||
NETIF_RSP_DROPPED);
|
||||
|
@ -578,8 +578,8 @@ again:
|
|||
/*
|
||||
* Do some sanity checks, and map the packet's page.
|
||||
*/
|
||||
if (txreq->size < ETHER_HDR_LEN ||
|
||||
txreq->size > (ETHER_MAX_LEN - ETHER_CRC_LEN)) {
|
||||
if (__predict_false(txreq->size < ETHER_HDR_LEN ||
|
||||
txreq->size > (ETHER_MAX_LEN - ETHER_CRC_LEN))) {
|
||||
printf("%s: packet size %d too big\n",
|
||||
ifp->if_xname, txreq->size);
|
||||
xennetback_tx_response(xneti, txreq->id,
|
||||
|
@ -588,7 +588,8 @@ again:
|
|||
continue;
|
||||
}
|
||||
/* don't cross page boundaries */
|
||||
if ((txreq->addr & PAGE_MASK) + txreq->size > PAGE_SIZE) {
|
||||
if (__predict_false(
|
||||
(txreq->addr & PAGE_MASK) + txreq->size > PAGE_SIZE)) {
|
||||
printf("%s: packet cross page boundary\n",
|
||||
ifp->if_xname);
|
||||
xennetback_tx_response(xneti, txreq->id,
|
||||
|
@ -598,7 +599,7 @@ again:
|
|||
}
|
||||
/* get a mbuf for this packet */
|
||||
MGETHDR(m, M_DONTWAIT, MT_DATA);
|
||||
if (m == NULL) {
|
||||
if (__predict_false(m == NULL)) {
|
||||
static struct timeval lasttime;
|
||||
if (ratecheck(&lasttime, &xni_pool_errintvl))
|
||||
printf("%s: mbuf alloc failed\n",
|
||||
|
@ -615,7 +616,7 @@ again:
|
|||
txreq->size, txreq->id, MASK_NETIF_TX_IDX(req_cons)));
|
||||
|
||||
pkt = pool_get(&xni_pkt_pool, PR_NOWAIT);
|
||||
if (pkt == NULL) {
|
||||
if (__predict_false(pkt == NULL)) {
|
||||
static struct timeval lasttime;
|
||||
if (ratecheck(&lasttime, &xni_pool_errintvl))
|
||||
printf("%s: xnbpkt alloc failed\n",
|
||||
|
@ -635,7 +636,7 @@ again:
|
|||
}
|
||||
if (pkt_page == NULL) {
|
||||
pkt_page = pool_get(&xni_page_pool, PR_NOWAIT);
|
||||
if (pkt_page == NULL) {
|
||||
if (__predict_false(pkt_page == NULL)) {
|
||||
static struct timeval lasttime;
|
||||
if (ratecheck(&lasttime, &xni_pool_errintvl))
|
||||
printf("%s: xnbpa alloc failed\n",
|
||||
|
@ -648,8 +649,8 @@ again:
|
|||
continue;
|
||||
}
|
||||
pkt_page->refcount = 0;
|
||||
if (xen_shm_map(&pkt_ma,
|
||||
1, xneti->domid, &pkt_va, 0) != 0) {
|
||||
if (__predict_false(xen_shm_map(&pkt_ma,
|
||||
1, xneti->domid, &pkt_va, 0) != 0)) {
|
||||
static struct timeval lasttime;
|
||||
if (ratecheck(&lasttime, &xni_pool_errintvl))
|
||||
printf("%s: can't map packet page\n",
|
||||
|
@ -658,6 +659,8 @@ again:
|
|||
NETIF_RSP_DROPPED);
|
||||
ifp->if_ierrors++;
|
||||
m_freem(m);
|
||||
pool_put(&xni_pkt_pool, pkt);
|
||||
pool_put(&xni_page_pool, pkt_page);
|
||||
continue;
|
||||
}
|
||||
XENPRINTF(("new pkt_page va 0x%lx mbuf %p\n",
|
||||
|
@ -671,6 +674,27 @@ again:
|
|||
XENPRINTF(("pkt_page refcount %d va 0x%lx m %p\n",
|
||||
pkt_page->refcount, pkt_va, m));
|
||||
}
|
||||
if ((ifp->if_flags & IFF_PROMISC) == 0) {
|
||||
struct ether_header *eh =
|
||||
(void*)(pkt_va | (txreq->addr & PAGE_MASK));
|
||||
if (ETHER_IS_MULTICAST(eh->ether_dhost) == 0 &&
|
||||
memcmp(LLADDR(ifp->if_sadl), eh->ether_dhost,
|
||||
ETHER_ADDR_LEN) != 0) {
|
||||
pool_put(&xni_pkt_pool, pkt);
|
||||
m_freem(m);
|
||||
if (pkt_page->refcount == 0) {
|
||||
xen_shm_unmap(pkt_page->va,
|
||||
&pkt_page->ma, 1, xneti->domid);
|
||||
SLIST_REMOVE(pkt_hash, pkt_page,
|
||||
xni_page, xni_page_next);
|
||||
pool_put(&xni_page_pool, pkt_page);
|
||||
}
|
||||
xennetback_tx_response(xneti, txreq->id,
|
||||
NETIF_RSP_OKAY);
|
||||
continue; /* packet is not for us */
|
||||
}
|
||||
}
|
||||
|
||||
if (MASK_NETIF_TX_IDX(req_cons + 1) ==
|
||||
MASK_NETIF_TX_IDX(xneti->xni_txring->resp_prod)) {
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue