@@ -356,11 +356,82 @@ ff_zc_mbuf_write(struct ff_zc_mbuf *zm, const char *data, int len)
356356}
357357
358358int
359- ff_zc_mbuf_read (struct ff_zc_mbuf * m , const char * data , int len )
359+ ff_zc_mbuf_read (struct ff_zc_mbuf * zm , char * data , int len )
360360{
361- // DOTO: Support read zero copy
362- return 0 ;
361+ struct mbuf * mb ;
362+ int progress = 0 , length , moff ;
363+
364+ if (zm == NULL || data == NULL || len <= 0 ) {
365+ return -1 ;
366+ }
367+
368+ /* For RECV, bsd_mbuf_off is the current mbuf cursor and `off` is the
369+ * already-consumed offset WITHIN that mbuf. Copy out up to `len` bytes,
370+ * spanning mbufs as needed. */
371+ mb = (struct mbuf * )zm -> bsd_mbuf_off ;
372+ moff = zm -> off ;
373+ while (mb != NULL && progress < len ) {
374+ length = min (mb -> m_len - moff , len - progress );
375+ bcopy (mtod (mb , char * ) + moff , data + progress , length );
376+ progress += length ;
377+ moff += length ;
378+ if (moff >= mb -> m_len ) {
379+ mb = mb -> m_next ;
380+ moff = 0 ;
381+ }
382+ }
383+ zm -> bsd_mbuf_off = mb ;
384+ zm -> off = moff ;
385+
386+ return progress ;
387+ }
388+
389+ #ifdef FSTACK_ZC_RECV
390+ /*
391+ * FSTACK_ZC_RECV: return the current segment's data pointer + length without
392+ * copying (pointer aliases into the underlying DPDK mbuf), then advance the
393+ * cursor to the next mbuf. Valid until ff_zc_recv_free() is called.
394+ */
395+ int
396+ ff_zc_mbuf_segment (struct ff_zc_mbuf * zm , void * * seg_data , int * seg_len )
397+ {
398+ struct mbuf * mb ;
399+
400+ if (zm == NULL || seg_data == NULL || seg_len == NULL ) {
401+ return -1 ;
402+ }
403+
404+ mb = (struct mbuf * )zm -> bsd_mbuf_off ;
405+ if (mb == NULL ) {
406+ return 0 ; /* chain exhausted */
407+ }
408+
409+ * seg_data = mtod (mb , void * );
410+ * seg_len = mb -> m_len ;
411+ zm -> bsd_mbuf_off = mb -> m_next ;
412+ zm -> off = 0 ;
413+
414+ return mb -> m_len ;
415+ }
416+
417+ /*
418+ * FSTACK_ZC_RECV: release the whole chain obtained from ff_zc_recv. m_freem
419+ * walks m_next and frees each mbuf; ext-mbuf segments trigger ff_mbuf_ext_free
420+ * which returns the backing DPDK mbuf seg (see docs/zc_read_spec). Idempotent.
421+ */
422+ void
423+ ff_zc_recv_free (struct ff_zc_mbuf * zm )
424+ {
425+ if (zm == NULL || zm -> bsd_mbuf == NULL ) {
426+ return ;
427+ }
428+ m_freem ((struct mbuf * )zm -> bsd_mbuf );
429+ zm -> bsd_mbuf = NULL ;
430+ zm -> bsd_mbuf_off = NULL ;
431+ zm -> off = 0 ;
432+ zm -> len = 0 ;
363433}
434+ #endif /* FSTACK_ZC_RECV */
364435
365436void *
366437ff_mbuf_gethdr (void * pkt , uint16_t total , void * data ,
0 commit comments