Skip to content

Commit b24fce9

Browse files
committed
Merge branch 'master' into github-master
2 parents 3c53901 + d904253 commit b24fce9

1 file changed

Lines changed: 81 additions & 80 deletions

File tree

sys/dev/netmap/netmap_generic.c

Lines changed: 81 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ static int
264264
generic_netmap_register(struct netmap_adapter *na, int enable)
265265
{
266266
struct netmap_generic_adapter *gna = (struct netmap_generic_adapter *)na;
267-
struct mbuf *m;
267+
struct netmap_kring *kring;
268268
int error;
269269
int i, r;
270270

@@ -281,14 +281,15 @@ generic_netmap_register(struct netmap_adapter *na, int enable)
281281
if (enable) { /* Enable netmap mode. */
282282
/* Init the mitigation support on all the rx queues. */
283283
gna->mit = malloc(na->num_rx_rings * sizeof(struct nm_generic_mit),
284-
M_DEVBUF, M_NOWAIT | M_ZERO);
284+
M_DEVBUF, M_NOWAIT | M_ZERO);
285285
if (!gna->mit) {
286286
D("mitigation allocation failed");
287287
error = ENOMEM;
288288
goto out;
289289
}
290-
for (r=0; r<na->num_rx_rings; r++)
290+
for (r=0; r<na->num_rx_rings; r++) {
291291
nm_os_mitigation_init(&gna->mit[r], r, na);
292+
}
292293

293294
/* Initialize the rx queue, as generic_rx_handler() can
294295
* be called as soon as nm_os_catch_rx() returns.
@@ -298,32 +299,29 @@ generic_netmap_register(struct netmap_adapter *na, int enable)
298299
}
299300

300301
/*
301-
* Preallocate packet buffers for the tx rings.
302+
* Prepare mbuf pools (parallel to the tx rings), for packet
303+
* transmission. Don't preallocate the mbufs here, it's simpler
304+
* to leave this task to txsync.
302305
*/
303-
for (r=0; r<na->num_tx_rings; r++)
306+
for (r=0; r<na->num_tx_rings; r++) {
304307
na->tx_rings[r].tx_pool = NULL;
308+
}
305309

306310
for (r=0; r<na->num_tx_rings; r++) {
307-
na->tx_rings[r].tx_pool = malloc(na->num_tx_desc * sizeof(struct mbuf *),
308-
M_DEVBUF, M_NOWAIT | M_ZERO);
309-
if (!na->tx_rings[r].tx_pool) {
311+
kring = &na->tx_rings[r];
312+
kring->tx_pool = malloc(na->num_tx_desc * sizeof(struct mbuf *),
313+
M_DEVBUF, M_NOWAIT | M_ZERO);
314+
if (!kring->tx_pool) {
310315
D("tx_pool allocation failed");
311316
error = ENOMEM;
312317
goto free_tx_pools;
313318
}
314-
for (i=0; i<na->num_tx_desc; i++)
315-
na->tx_rings[r].tx_pool[i] = NULL;
316319
for (i=0; i<na->num_tx_desc; i++) {
317-
m = nm_os_get_mbuf(na->ifp, NETMAP_BUF_SIZE(na));
318-
if (!m) {
319-
D("tx_pool[%d] allocation failed", i);
320-
error = ENOMEM;
321-
goto free_tx_pools;
322-
}
323-
na->tx_rings[r].tx_pool[i] = m;
320+
kring->tx_pool[i] = NULL;
324321
}
325-
na->tx_rings[r].tx_event = NULL;
326-
mtx_init(&na->tx_rings[r].tx_event_lock,
322+
323+
kring->tx_event = NULL;
324+
mtx_init(&kring->tx_event_lock,
327325
"tx_event_lock", NULL, MTX_SPIN);
328326
}
329327

@@ -383,32 +381,35 @@ generic_netmap_register(struct netmap_adapter *na, int enable)
383381
mbq_safe_fini(&na->rx_rings[r].rx_queue);
384382
}
385383

386-
for (r=0; r<na->num_rx_rings; r++)
384+
for (r=0; r<na->num_rx_rings; r++) {
387385
nm_os_mitigation_cleanup(&gna->mit[r]);
386+
}
388387
free(gna->mit, M_DEVBUF);
389388

390389
/* Decrement reference counter for the mbufs in the
391390
* TX pools. These mbufs can be still pending in drivers,
392391
* (e.g. this happens with virtio-net driver, which
393392
* does lazy reclaiming of transmitted mbufs). */
394393
for (r=0; r<na->num_tx_rings; r++) {
394+
kring = &na->tx_rings[r];
395395
/* We must remove the destructor on the TX event,
396396
* because the destructor invokes netmap code, and
397397
* the netmap module may disappear before the
398398
* TX event is consumed. */
399-
mtx_lock(&na->tx_rings[r].tx_event_lock);
400-
m = na->tx_rings[r].tx_event;
401-
if (m) {
402-
SET_MBUF_DESTRUCTOR(m, NULL);
399+
mtx_lock(&kring->tx_event_lock);
400+
if (kring->tx_event) {
401+
SET_MBUF_DESTRUCTOR(kring->tx_event, NULL);
403402
}
404-
na->tx_rings[r].tx_event = NULL;
405-
mtx_unlock(&na->tx_rings[r].tx_event_lock);
406-
mtx_destroy(&na->tx_rings[r].tx_event_lock);
403+
kring->tx_event = NULL;
404+
mtx_unlock(&kring->tx_event_lock);
405+
mtx_destroy(&kring->tx_event_lock);
407406

408407
for (i=0; i<na->num_tx_desc; i++) {
409-
m_freem(na->tx_rings[r].tx_pool[i]);
408+
if (kring->tx_pool[i]) {
409+
m_freem(kring->tx_pool[i]);
410+
}
410411
}
411-
free(na->tx_rings[r].tx_pool, M_DEVBUF);
412+
free(kring->tx_pool, M_DEVBUF);
412413
}
413414

414415
#ifdef RATE_GENERIC
@@ -434,11 +435,9 @@ generic_netmap_register(struct netmap_adapter *na, int enable)
434435
rtnl_unlock();
435436
free_tx_pools:
436437
for (r=0; r<na->num_tx_rings; r++) {
437-
if (na->tx_rings[r].tx_pool == NULL)
438+
if (na->tx_rings[r].tx_pool == NULL) {
438439
continue;
439-
for (i=0; i<na->num_tx_desc; i++)
440-
if (na->tx_rings[r].tx_pool[i])
441-
m_freem(na->tx_rings[r].tx_pool[i]);
440+
}
442441
free(na->tx_rings[r].tx_pool, M_DEVBUF);
443442
na->tx_rings[r].tx_pool = NULL;
444443
}
@@ -512,51 +511,46 @@ generic_netmap_tx_clean(struct netmap_kring *kring, int txqdisc)
512511

513512
while (nm_i != hwcur) { /* buffers not completed */
514513
struct mbuf *m = tx_pool[nm_i];
515-
int replenish = 0;
516514

517515
if (txqdisc) {
518-
if (MBUF_QUEUED(m)) {
516+
if (m == NULL) {
517+
/* Nothing to do, this is going
518+
* to be replenished. */
519+
RD(3, "Is this happening?");
520+
521+
} else if (MBUF_QUEUED(m)) {
519522
break; /* Not dequeued yet. */
520523

521524
} else if (MBUF_REFCNT(m) != 1) {
522525
/* This mbuf has been dequeued but is still busy
523526
* (refcount is 2).
524-
* Leave it to the driver and realloc. */
527+
* Leave it to the driver and replenish. */
525528
m_freem(m);
526-
replenish = 1;
529+
tx_pool[nm_i] = NULL;
527530
}
528531

529532
} else {
530533
if (unlikely(m == NULL)) {
531-
/* This slot has been used to place an event. */
534+
int event_consumed;
535+
536+
/* This slot was used to place an event. */
532537
mtx_lock(&kring->tx_event_lock);
533-
replenish = (kring->tx_event == NULL);
538+
event_consumed = (kring->tx_event == NULL);
534539
mtx_unlock(&kring->tx_event_lock);
535-
if (!replenish) {
540+
if (!event_consumed) {
536541
/* The event has not been consumed yet,
537542
* still busy in the driver. */
538543
break;
539544
}
540-
/* The event has been consumed, we have to
541-
* replenish it and go ahead. */
545+
/* The event has been consumed, we can go
546+
* ahead. */
542547

543548
} else if (MBUF_REFCNT(m) != 1) {
544549
/* This mbuf is still busy: its refcnt is 2. */
545550
break;
546551
}
547552
}
548553

549-
if (replenish) {
550-
tx_pool[nm_i] = m = nm_os_get_mbuf(kring->na->ifp,
551-
NETMAP_BUF_SIZE(kring->na));
552-
if (unlikely(m == NULL)) {
553-
D("mbuf allocation failed, XXX error");
554-
// XXX how do we proceed ? break ?
555-
return -ENOMEM;
556-
}
557-
IFRATE(rate_ctx.new.txrepl++);
558-
}
559-
560554
n++;
561555
nm_i = nm_next(nm_i, lim);
562556
#if 0 /* rate adaptation */
@@ -686,8 +680,6 @@ generic_netmap_txsync(struct netmap_kring *kring, int flags)
686680

687681
IFRATE(rate_ctx.new.txsync++);
688682

689-
// TODO: handle the case of mbuf allocation failure
690-
691683
rmb();
692684

693685
/*
@@ -722,27 +714,35 @@ generic_netmap_txsync(struct netmap_kring *kring, int flags)
722714

723715
NM_CHECK_ADDR_LEN(na, addr, len);
724716

725-
/* Tale a mbuf from the tx pool and copy in the user packet. */
717+
/* Tale a mbuf from the tx pool (replenishing the pool
718+
* entry if necessary) and copy in the user packet. */
726719
m = kring->tx_pool[nm_i];
727-
if (unlikely(!m)) {
728-
RD(5, "This should never happen");
729-
kring->tx_pool[nm_i] = m = nm_os_get_mbuf(na->ifp, NETMAP_BUF_SIZE(na));
730-
if (unlikely(m == NULL)) {
731-
D("mbuf allocation failed");
720+
if (unlikely(m == NULL)) {
721+
kring->tx_pool[nm_i] = m =
722+
nm_os_get_mbuf(ifp, NETMAP_BUF_SIZE(na));
723+
if (m == NULL) {
724+
RD(2, "Failed to replenish mbuf");
725+
/* Here we could schedule a timer which
726+
* retries to replenish after a while,
727+
* and notifies the client when it
728+
* manages to replenish some slots. In
729+
* any case we break early to avoid
730+
* crashes. */
732731
break;
733732
}
733+
IFRATE(rate_ctx.new.txrepl++);
734734
}
735+
735736
a.m = m;
736737
a.addr = addr;
737738
a.len = len;
738739
a.qevent = (nm_i == event);
739-
/* XXX When not in txqdisc mode, we should ask
740-
* notifications when NS_REPORT is set,
741-
* or roughly every half ring. We can optimize this
742-
* by lazily requesting notifications only when a
743-
* transmission fails. Probably the best way is to
744-
* break on failures and set notifications when
745-
* ring->cur == ring->tail || nm_i != cur
740+
/* When not in txqdisc mode, we should ask
741+
* notifications when NS_REPORT is set, or roughly
742+
* every half ring. To optimize this, we set a
743+
* notification event when the client runs out of
744+
* TX ring space, or when transmission fails. In
745+
* the latter case we also break early.
746746
*/
747747
tx_ret = nm_os_generic_xmit_frame(&a);
748748
if (unlikely(tx_ret)) {
@@ -793,8 +793,9 @@ generic_netmap_txsync(struct netmap_kring *kring, int flags)
793793
a.addr = NULL;
794794
nm_os_generic_xmit_frame(&a);
795795
}
796-
/* Update hwcur to the next slot to transmit. */
797-
kring->nr_hwcur = nm_i; /* not head, we could break early */
796+
/* Update hwcur to the next slot to transmit. Here nm_i
797+
* is not necessarily head, we could break early. */
798+
kring->nr_hwcur = nm_i;
798799
}
799800

800801
/*
@@ -830,20 +831,20 @@ generic_rx_handler(struct ifnet *ifp, struct mbuf *m)
830831
struct netmap_generic_adapter *gna = (struct netmap_generic_adapter *)na;
831832
struct netmap_kring *kring;
832833
u_int work_done;
833-
u_int rr = MBUF_RXQ(m); // receive ring number
834+
u_int r = MBUF_RXQ(m); /* receive ring number */
834835

835-
if (rr >= na->num_rx_rings) {
836-
rr = rr % na->num_rx_rings; // XXX expensive...
836+
if (r >= na->num_rx_rings) {
837+
r = r % na->num_rx_rings;
837838
}
838839

839-
kring = &na->rx_rings[rr];
840+
kring = &na->rx_rings[r];
840841

841842
/* limit the size of the queue */
842843
if (unlikely(!gna->rxsg && MBUF_LEN(m) > kring->ring->nr_buf_size)) {
843844
/* This may happen when GRO/LRO features are enabled for
844845
* the NIC driver when the generic adapter does not
845846
* support RX scatter-gather. */
846-
RD(5, "Warning: driver pushed up big packet "
847+
RD(2, "Warning: driver pushed up big packet "
847848
"(size=%d)", (int)MBUF_LEN(m));
848849
m_freem(m);
849850
} else if (unlikely(mbq_len(&kring->rx_queue) > 1024)) {
@@ -854,17 +855,17 @@ generic_rx_handler(struct ifnet *ifp, struct mbuf *m)
854855

855856
if (netmap_generic_mit < 32768) {
856857
/* no rx mitigation, pass notification up */
857-
netmap_generic_irq(na, rr, &work_done);
858+
netmap_generic_irq(na, r, &work_done);
858859
} else {
859860
/* same as send combining, filter notification if there is a
860861
* pending timer, otherwise pass it up and start a timer.
861862
*/
862-
if (likely(nm_os_mitigation_active(&gna->mit[rr]))) {
863+
if (likely(nm_os_mitigation_active(&gna->mit[r]))) {
863864
/* Record that there is some pending work. */
864-
gna->mit[rr].mit_pending = 1;
865+
gna->mit[r].mit_pending = 1;
865866
} else {
866-
netmap_generic_irq(na, rr, &work_done);
867-
nm_os_mitigation_start(&gna->mit[rr]);
867+
netmap_generic_irq(na, r, &work_done);
868+
nm_os_mitigation_start(&gna->mit[r]);
868869
}
869870
}
870871
}

0 commit comments

Comments
 (0)