xref: /netbsd-src/share/man/man9/mbuf.9 (revision 16dce51364ebe8aeafbae46bc5aa167b8115bc45)
1.\"	$NetBSD: mbuf.9,v 1.57 2018/04/10 16:12:29 maxv Exp $
2.\"
3.\" Copyright (c) 1997 The NetBSD Foundation, Inc.
4.\" All rights reserved.
5.\"
6.\" This documentation is derived from text contributed to The NetBSD Foundation
7.\" by S.P.Zeidler (aka stargazer).
8.\"
9.\" Redistribution and use in source and binary forms, with or without
10.\" modification, are permitted provided that the following conditions
11.\" are met:
12.\" 1. Redistributions of source code must retain the above copyright
13.\"    notice, this list of conditions and the following disclaimer.
14.\" 2. Redistributions in binary form must reproduce the above copyright
15.\"    notice, this list of conditions and the following disclaimer in the
16.\"    documentation and/or other materials provided with the distribution.
17.\"
18.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21.\" PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28.\" POSSIBILITY OF SUCH DAMAGE.
29.\"
30.Dd April 10, 2018
31.Dt MBUF 9
32.Os
33.Sh NAME
34.Nm mbuf ,
35.Nm m_get ,
36.Nm m_gethdr ,
37.Nm m_devget ,
38.Nm m_copym ,
39.Nm m_copypacket ,
40.Nm m_copydata ,
41.Nm m_copyback ,
42.Nm m_copyback_cow ,
43.Nm m_cat ,
44.Nm m_dup ,
45.Nm m_makewritable ,
46.Nm m_prepend ,
47.Nm m_pulldown ,
48.Nm m_pullup ,
49.Nm m_copyup ,
50.Nm m_split ,
51.Nm m_adj ,
52.Nm m_apply ,
53.Nm m_free ,
54.Nm m_freem ,
55.Nm mtod ,
56.Nm MGET ,
57.Nm MGETHDR ,
58.Nm MEXTMALLOC ,
59.Nm MEXTADD ,
60.Nm MCLGET ,
61.Nm M_COPY_PKTHDR ,
62.Nm M_MOVE_PKTHDR ,
63.Nm M_ALIGN ,
64.Nm MH_ALIGN ,
65.Nm M_LEADINGSPACE ,
66.Nm M_TRAILINGSPACE ,
67.Nm M_PREPEND ,
68.Nm MCHTYPE
69.Nd "functions and macros for managing memory used by networking code"
70.Sh SYNOPSIS
71.In sys/mbuf.h
72.Ft struct mbuf *
73.Fn m_get "int nowait" "int type"
74.Ft struct mbuf *
75.Fn m_gethdr "int nowait" "int type"
76.Ft struct mbuf *
77.Fn m_devget "char *buf" "int totlen" "int off0" "struct ifnet *ifp" "void (*copy)(const void *, void *, size_t)"
78.Ft struct mbuf *
79.Fn m_copym "struct mbuf *m" "int off0" "int len" "int wait"
80.Ft struct mbuf *
81.Fn m_copypacket "struct mbuf *m" "int how"
82.Ft void
83.Fn m_copydata "struct mbuf *m" "int off" "int len" "void *cp"
84.Ft void
85.Fn m_copyback "struct mbuf *m0" "int off" "int len" "void *cp"
86.Ft struct mbuf *
87.Fn m_copyback_cow "struct mbuf *m0" "int off" "int len" "void *cp" "int how"
88.Ft int
89.Fn m_makewritable "struct mbuf **mp" "int off" "int len" "int how"
90.Ft void
91.Fn m_cat "struct mbuf *m" "struct mbuf *n"
92.Ft struct mbuf *
93.Fn m_dup "struct mbuf *m" "int off0" "int len" "int wait"
94.Ft struct mbuf *
95.Fn m_prepend "struct mbuf *m" "int len" "int how"
96.Ft struct mbuf *
97.Fn m_pulldown "struct mbuf *m" "int off" "int len" "int *offp"
98.Ft struct mbuf *
99.Fn m_pullup "struct mbuf *n" "int len"
100.Ft struct mbuf *
101.Fn m_copyup "struct mbuf *m" "int len" "int dstoff"
102.Ft struct mbuf *
103.Fn m_split "struct mbuf *m0" "int len0" "int wait"
104.Ft void
105.Fn m_adj "struct mbuf *mp" "int req_len"
106.Ft int
107.Fn m_apply "struct mbuf *m" "int off" "int len" "int *f(void *, void *, unsigned int)" "void *arg"
108.Ft struct mbuf *
109.Fn m_free "struct mbuf *m"
110.Ft void
111.Fn m_freem "struct mbuf *m"
112.Ft datatype
113.Fn mtod "struct mbuf *m" "datatype"
114.Ft void
115.Fn MGET "struct mbuf *m" "int how" "int type"
116.Ft void
117.Fn MGETHDR "struct mbuf *m" "int how" "int type"
118.Ft void
119.Fn MEXTMALLOC "struct mbuf *m" "int len" "int how"
120.Ft void
121.Fn MEXTADD "struct mbuf *m" "void *buf" "int size" "int type" "void (*free)(struct mbuf *, void *, size_t, void *)" "void *arg"
122.Ft void
123.Fn MCLGET "struct mbuf *m" "int how"
124.Ft void
125.Fn M_COPY_PKTHDR "struct mbuf *to" "struct mbuf *from"
126.Ft void
127.Fn M_MOVE_PKTHDR "struct mbuf *to" "struct mbuf *from"
128.Ft void
129.Fn M_ALIGN "struct mbuf *m" "int len"
130.Ft void
131.Fn MH_ALIGN "struct mbuf *m" "int len"
132.Ft int
133.Fn M_LEADINGSPACE "struct mbuf *m"
134.Ft int
135.Fn M_TRAILINGSPACE "struct mbuf *m"
136.Ft void
137.Fn M_PREPEND "struct mbuf *m" "int plen" "int how"
138.Ft void
139.Fn MCHTYPE "struct mbuf *m" "int type"
140.Sh DESCRIPTION
141The
142.Nm
143functions and macros provide an easy and consistent way to handle
144a networking stack's memory management needs.
145An
146.Nm
147consists of a header and a data area.
148It is of a fixed size,
149.Dv MSIZE
150.Pq defined in Aq Pa machine/param.h ,
151which includes overhead.
152The header contains a pointer to the next
153.Nm
154in the
155.Sq "mbuf chain" ,
156a pointer to the next
157.Sq "mbuf chain" ,
158a pointer to the data area, the amount of data in this mbuf, its type
159and a
160.Dv flags
161field.
162.Pp
163The
164.Dv type
165variable can signify:
166.Bl -tag -compact -offset indent -width "XXXXXXXXXXX"
167.It Dv MT_FREE
168the mbuf should be on the ``free'' list
169.It Dv MT_DATA
170data was dynamically allocated
171.It Dv MT_HEADER
172data is a packet header
173.It Dv MT_SONAME
174data is a socket name
175.It Dv MT_SOOPTS
176data is socket options
177.It Dv MT_FTABLE
178data is the fragment reassembly header
179.It Dv MT_CONTROL
180mbuf contains ancillary \&(protocol control\&) data
181.It Dv MT_OOBDATA
182mbuf contains out-of-band data.
183.El
184.Pp
185The
186.Dv flags
187variable contains information describing the
188.Nm ,
189notably:
190.Bl -tag -compact -offset indent -width "XXXXXXXXXXX"
191.It Dv M_EXT
192has external storage
193.It Dv M_PKTHDR
194is start of record
195.It Dv M_EOR
196is end of record
197.It Dv M_CLUSTER
198external storage is a cluster.
199.El
200.Pp
201If an
202.Nm
203designates the start of a record
204.Pq Dv M_PKTHDR ,
205its
206.Dv flags
207field may contain additional information describing the content of
208the record:
209.Bl -tag -compact -offset indent -width "XXXXXXXXXXX"
210.It Dv M_BCAST
211sent/received as link-level broadcast
212.It Dv M_MCAST
213sent/received as link-level multicast
214.It Dv M_LINK0 ,
215.It Dv M_LINK1 ,
216.It Dv M_LINK2
217three link-level specific flags.
218.El
219.Pp
220An
221.Nm
222may add a single
223.Sq "mbuf cluster"
224of
225.Dv MCLBYTES
226bytes
227.Pq also defined in Aq Pa machine/param.h ,
228which has no additional overhead
229and is used instead of the internal data area; this is done when at least
230.Dv MINCLSIZE
231bytes of data must be stored.
232.Pp
233When the
234.Dv M_EXT
235flag is raised for an mbuf,
236the external storage area could be shared among multiple mbufs.
237Be careful when you attempt to overwrite the data content of the mbuf.
238.Bl -tag -width compact
239.It Fn m_get "int nowait" "int type"
240Allocates an mbuf and initializes it to contain internal data.
241The
242.Fa nowait
243parameter is a choice of
244.Dv M_WAIT / M_DONTWAIT
245from caller.
246.Dv M_WAIT
247means the call cannot fail, but may take forever.
248The
249.Fa type
250parameter is an mbuf type.
251.It Fn m_gethdr "int nowait" "int type"
252Allocates an mbuf and initializes it to contain a packet header and internal
253data.
254The
255.Fa nowait
256parameter is a choice of
257.Dv M_WAIT / M_DONTWAIT
258from caller.
259The
260.Fa type
261parameter is an mbuf type.
262.It Fn m_devget "char *buf" "int totlen" "int off0" "struct ifnet *ifp" "void (*copy)(const void *, void *, size_t)"
263Copies
264.Fa len
265bytes from device local memory into mbufs using copy routine
266.Fa copy .
267If parameter
268.Fa off
269is non-zero, the packet is supposed to be trailer-encapsulated and
270.Fa off
271bytes plus the type and length fields will be skipped before copying.
272Returns the top of the mbuf chain it created.
273.It Fn m_copym "struct mbuf *m" "int off0" "int len" "int wait"
274Creates a copy of an mbuf chain starting
275.Fa off0
276bytes from the beginning, continuing for
277.Fa len
278bytes.
279If the
280.Fa len
281requested is
282.Dv M_COPYALL ,
283the complete mbuf chain will be copied.
284The
285.Fa wait
286parameter is a choice of
287.Dv M_WAIT / M_DONTWAIT
288from caller.
289.It Fn m_copypacket "struct mbuf *m" "int how"
290Copies an entire packet, including header (which must be present).
291This function is an optimization of the common case
292.Li m_copym ( m , 0 , Dv M_COPYALL , Fa how ) .
293.It Fn m_copydata "struct mbuf *m" "int off" "int len" "void *cp"
294Copies
295.Fa len
296bytes data from mbuf chain
297.Fa m
298into the buffer
299.Fa cp ,
300starting
301.Fa off
302bytes from the beginning.
303.It Fn m_copyback "struct mbuf *m0" "int off" "int len" "void *cp"
304Copies
305.Fa len
306bytes data from buffer
307.Fa cp
308back into the mbuf chain
309.Fa m0 ,
310starting
311.Fa off
312bytes from the beginning of the chain, extending the mbuf chain if necessary.
313.Fn m_copyback
314can only fail when extending the chain.
315The caller should check for this kind of failure
316by checking the resulting length of the chain in that case.
317It is an error to use
318.Fn m_copyback
319on read-only mbufs.
320.It Fn m_copyback_cow "struct mbuf *m0" "int off" "int len" "void *cp" \
321"int how"
322Copies
323.Fa len
324bytes data from buffer
325.Fa cp
326back into the mbuf chain
327.Fa m0
328as
329.Fn m_copyback
330does.
331Unlike
332.Fn m_copyback ,
333it is safe to use
334.Fn m_copyback_cow
335on read-only mbufs.
336If needed,
337.Fn m_copyback_cow
338automatically allocates new mbufs and adjusts the chain.
339On success, it returns a pointer to the resulting mbuf chain,
340and frees the original mbuf
341.Fa m0 .
342Otherwise, it returns
343.Dv NULL .
344The
345.Fa how
346parameter is a choice of
347.Dv M_WAIT / M_DONTWAIT
348from the caller.
349Unlike
350.Fn m_copyback ,
351extending the mbuf chain isn't supported.
352It is an error to attempt to extend the mbuf chain using
353.Fn m_copyback_cow .
354.It Fn m_makewritable "struct mbuf **mp" "int off" "int len" "int how"
355Rearranges an mbuf chain so that
356.Fa len
357bytes from offset
358.Fa off
359are writable.
360When it meets read-only mbufs, it allocates new mbufs, adjusts the chain as
361.Fn m_copyback_cow
362does, and copies the original content into them.
363.Fn m_makewritable
364does
365.Em not
366guarantee that all
367.Fa len
368bytes at
369.Fa off
370are consecutive.
371The
372.Fa how
373parameter is a choice of
374.Dv M_WAIT / M_DONTWAIT
375from the caller.
376.Fn m_makewritable
377preserves the contents of the mbuf chain even in the case of failure.
378It updates a pointer to the mbuf chain pointed to by
379.Fa mp .
380It returns 0 on success.
381Otherwise, it returns an error code, typically
382.Er ENOBUFS .
383.It Fn m_cat "struct mbuf *m" "struct mbuf *n"
384Concatenates mbuf chain
385.Fa n
386to
387.Fa m .
388Both chains must be of the same type; packet headers will
389.Em not
390be updated if present.
391.It Fn m_dup "struct mbuf *m" "int off0" "int len" "int wait"
392Similarly to
393.Fn m_copym ,
394the function creates a copy of an mbuf chain starting
395.Fa off0
396bytes from the beginning, continuing for
397.Fa len
398bytes.
399While
400.Fn m_copym
401tries to share external storage for mbufs with
402.Dv M_EXT
403flag,
404.Fn m_dup
405will deep-copy the whole data content into new mbuf chain
406and avoids shared external storage.
407.It Fn m_prepend "struct mbuf *m" "int len" "int how"
408Lesser-used path for
409.Fn M_PREPEND :
410allocates new mbuf
411.Fa m
412of size
413.Fa len
414to prepend to the chain, copying junk along.
415The
416.Fa how
417parameter is a choice of
418.Dv M_WAIT / M_DONTWAIT
419from caller.
420It is illegal for the
421.Fa len
422parameter to be greater than
423.Dv MHLEN .
424.It Fn m_pulldown "struct mbuf *m" "int off" "int len" "int *offp"
425Rearranges an mbuf chain so that
426.Fa len
427bytes from offset
428.Fa off
429are contiguous and in the data area of an mbuf.
430The return value points to an mbuf in the middle of the mbuf chain
431.Fa m .
432If we call the return value
433.Fa n ,
434the contiguous data region is available at
435.Li "mtod(n, void *) + *offp" ,
436or
437.Li "mtod(n, void *)"
438if
439.Fa offp
440is
441.Dv NULL .
442The top of the mbuf chain
443.Fa m ,
444and mbufs up to
445.Fa off ,
446will not be modified.
447On successful return, it is guaranteed that the mbuf pointed to by
448.Fa n
449does not have a shared external storage,
450therefore it is safe to update the contiguous region.
451Returns
452.Dv NULL
453and frees the mbuf chain on failure.
454.Fa len
455must be smaller than or equal to
456.Dv MCLBYTES .
457.It Fn m_pullup "struct mbuf *m" "int len"
458Rearranges an mbuf chain so that
459.Fa len
460bytes are contiguous
461and in the data area of an mbuf (so that
462.Fn mtod
463will work for a structure of size
464.Fa len ) .
465Returns the resulting
466mbuf chain on success, frees it and returns
467.Dv NULL
468on failure.
469If there is room, it will add up to
470.Dv max_protohdr
471-
472.Fa len
473extra bytes to the
474contiguous region to possibly avoid being called again.
475.Fa len
476must be smaller or equal than
477.Dv MHLEN .
478.It Fn m_copyup "struct mbuf *m" "int len" "int dstoff"
479Similar to
480.Fn m_pullup
481but copies
482.Fa len
483bytes of data into a new mbuf at
484.Fa dstoff
485bytes into the mbuf.
486The
487.Fa dstoff
488argument aligns the data and leaves room for a link layer header.
489Returns the new
490mbuf chain on success, and frees the mbuf chain and returns
491.Dv NULL
492on failure.
493Note that
494the function does not allocate mbuf clusters, so
495.Fa len + dstoff
496must be less than
497.Dv MHLEN .
498.It Fn m_split "struct mbuf *m0" "int len0" "int wait"
499Partitions an mbuf chain in two pieces, returning the tail,
500which is all but the first
501.Fa len0
502bytes.
503In case of failure, it returns
504.Dv NULL
505and restores the chain to its original state.
506.It Fn m_adj "struct mbuf *mp" "int req_len"
507Shaves off
508.Fa req_len
509bytes from head or tail of the (valid) data area.
510If
511.Fa req_len
512is greater than zero, front bytes are being shaved off, if it's smaller,
513from the back (and if it is zero, the mbuf will stay bearded).
514This function does not move data in any way, but is used to manipulate the
515data area pointer and data length variable of the mbuf in a non-clobbering
516way.
517.It Fn m_apply "struct mbuf *m" "int off" "int len" "int (*f)(void *, void *, unsigned int)" "void *arg"
518Apply function
519.Fa f
520to the data in an mbuf chain starting
521.Fa off
522bytes from the beginning, continuing for
523.Fa len
524bytes.
525Neither
526.Fa off
527nor
528.Fa len
529may be negative.
530.Fa arg
531will be supplied as first argument for
532.Fa f ,
533the second argument will be the pointer to the data buffer of a
534packet (starting after
535.Fa off
536bytes in the stream), and the third argument is the amount
537of data in bytes in this call.
538If
539.Fa f
540returns something not equal to zero
541.Fn m_apply
542will bail out, returning the return code of
543.Fa f .
544Upon successful completion it will return zero.
545.It Fn m_free "struct mbuf *m"
546Frees mbuf
547.Fa m .
548.It Fn m_freem "struct mbuf *m"
549Frees the mbuf chain beginning with
550.Fa m .
551This function contains the elementary sanity check for a
552.Dv NULL
553pointer.
554.It Fn mtod "struct mbuf *m" "datatype"
555Returns a pointer to the data contained in the specified mbuf
556.Fa m ,
557type-casted to the specified data type
558.Fa datatype .
559Implemented as a macro.
560.It Fn MGET "struct mbuf *m" "int how" "int type"
561Allocates mbuf
562.Fa m
563and initializes it to contain internal data.
564See
565.Fn m_get .
566Implemented as a macro.
567.It Fn MGETHDR "struct mbuf *m" "int how" "int type"
568Allocates mbuf
569.Fa m
570and initializes it to contain a packet header.
571See
572.Fn m_gethdr .
573Implemented as a macro.
574.It Fn MEXTMALLOC "struct mbuf *m" "int len" "int how"
575Allocates external storage of size
576.Fa len
577for mbuf
578.Fa m .
579The
580.Fa how
581parameter is a choice of
582.Dv M_WAIT / M_DONTWAIT
583from caller.
584The flag
585.Dv M_EXT
586is set upon success.
587Implemented as a macro.
588.It Fn MEXTADD "struct mbuf *m" "void *buf" "int size" "int type" "void (*free)(struct mbuf *, void *, size_t, void *)" "void *arg"
589Adds pre-allocated external storage
590.Fa buf
591to a normal mbuf
592.Fa m ;
593the parameters
594.Fa size ,
595.Fa type ,
596.Fa free
597and
598.Fa arg
599describe the external storage.
600.Fa size
601is the size of the storage,
602.Fa type
603describes its
604.Xr malloc 9
605type,
606.Fa free
607is a free routine (if not the usual one), and
608.Fa arg
609is a possible argument to the free routine.
610The flag
611.Dv M_EXT
612is set upon success.
613Implemented as a macro.
614If a free routine is specified, it will be called when the mbuf is freed.
615In the case of former, the first argument for a free routine is the mbuf
616.Fa m
617and the routine is expected to free it in addition to the external storage
618pointed by second argument.
619In the case of latter, the first argument for the routine is NULL.
620.It Fn MCLGET "struct mbuf *m" "int how"
621Allocates and adds an mbuf cluster to a normal mbuf
622.Fa m .
623The
624.Fa how
625parameter is a choice of
626.Dv M_WAIT / M_DONTWAIT
627from caller.
628The flag
629.Dv M_EXT
630is set upon success.
631Implemented as a macro.
632.It Fn M_COPY_PKTHDR "struct mbuf *to" "struct mbuf *from"
633Copies the mbuf pkthdr from mbuf
634.Fa from
635to mbuf
636.Fa to .
637.Fa from
638must have the type flag
639.Dv M_PKTHDR
640set, and
641.Fa to
642must be empty.
643Implemented as a macro.
644.It Fn M_MOVE_PKTHDR "struct mbuf *to" "struct mbuf *from"
645Moves the mbuf pkthdr from mbuf
646.Fa from
647to mbuf
648.Fa to .
649.Fa from
650must have the type flag
651.Dv M_PKTHDR
652set, and
653.Fa to
654must be empty.
655The flag
656.Dv M_PKTHDR
657in mbuf
658.Fa from
659will be cleared.
660.It Fn M_ALIGN "struct mbuf *m" "int len"
661Sets the data pointer of a newly allocated mbuf
662.Fa m
663to
664.Fa len
665bytes from the end of the mbuf data area, so that
666.Fa len
667bytes of data written to the mbuf
668.Fa m ,
669starting at the data pointer, will be aligned to the end of the data area.
670Implemented as a macro.
671.It Fn MH_ALIGN "struct mbuf *m" "int len"
672Sets the data pointer of a newly allocated packetheader mbuf
673.Fa m
674to
675.Fa len
676bytes from the end of the mbuf data area, so that
677.Fa len
678bytes of data written to the mbuf
679.Fa m ,
680starting at the data pointer, will be aligned to the end of the data area.
681Implemented as a macro.
682.It Fn M_LEADINGSPACE "struct mbuf *m"
683Returns the amount of space available before the current start of valid
684data in mbuf
685.Fa m .
686Returns 0 if the mbuf data part is shared across multiple mbufs
687.Pq i.e. not writable .
688Implemented as a macro.
689.It Fn M_TRAILINGSPACE "struct mbuf *m"
690Returns the amount of space available after the current end of valid
691data in mbuf
692.Fa m .
693Returns 0 if the mbuf data part is shared across multiple mbufs
694.Pq i.e. not writable .
695Implemented as a macro.
696.It Fn M_PREPEND "struct mbuf *m" "int plen" "int how"
697Prepends space of size
698.Fa plen
699to mbuf
700.Fa m .
701If a new mbuf must be allocated,
702.Fa how
703specifies whether to wait.
704If
705.Fa how
706is
707.Dv M_DONTWAIT
708and allocation fails, the original mbuf chain is freed and
709.Fa m
710is set to
711.Dv NULL .
712Implemented as a macro.
713.It Fn MCHTYPE "struct mbuf *m" "int type"
714Change mbuf
715.Fa m
716to new type
717.Fa type .
718Implemented as a macro.
719.El
720.Sh CODE REFERENCES
721The
722.Nm
723management functions are implemented within the file
724.Pa sys/kern/uipc_mbuf.c .
725Function prototypes, and the functions implemented as macros
726are located in
727.Pa sys/sys/mbuf.h .
728.Sh SEE ALSO
729.Pa /usr/share/doc/smm/18.net ,
730.Xr netstat 1 ,
731.Xr m_tag 9 ,
732.Xr malloc 9
733.Rs
734.%A Jun-ichiro Hagino
735.%T "Mbuf issues in 4.4BSD IPv6/IPsec support (experiences from KAME IPv6/IPsec implementation)"
736.%B "Proceedings of the freenix track: 2000 USENIX annual technical conference"
737.%D June 2000
738.Re
739.Sh AUTHORS
740.An -nosplit
741The original mbuf data structures were designed by Rob Gurwitz
742when he did the initial TCP/IP implementation at BBN.
743.Pp
744Further extensions and enhancements were made by Bill Joy, Sam Leffler,
745and Mike Karels at CSRG.
746.Pp
747Current implementation of external storage by
748.An Matt Thomas
749.Aq matt@3am-software.com
750and
751.An Jason R. Thorpe
752.Aq thorpej@NetBSD.org .
753