@@ -264,7 +264,7 @@ static int
264264generic_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 ();
435436free_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