xref: /openbsd-src/share/man/man9/mbuf.9 (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1.\"     $OpenBSD: mbuf.9,v 1.43 2009/03/02 23:37:08 blambert Exp $
2.\"
3.\" Copyright (c) 2001 Jean-Jacques Bernard-Gundol <jjbg@openbsd.org>
4.\" All rights reserved.
5.\"
6.\" Redistribution and use in source and binary forms, with or without
7.\" modification, are permitted provided that the following conditions
8.\" are met:
9.\" 1. Redistributions of source code must retain the above copyright
10.\"    notice, this list of conditions and the following disclaimer.
11.\" 2. Redistributions in binary form must reproduce the above copyright
12.\"    notice, this list of conditions and the following disclaimer in the
13.\"    documentation and/or other materials provided with the distribution.
14.\" 3. The name of the author may not be used to endorse or promote products
15.\"    derived from this software without specific prior written permission
16.\"
17.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27.\"
28.Dd $Mdocdate: March 2 2009 $
29.Dt MBUF 9
30.Os
31.Sh NAME
32.Nm mbuf
33.Nd Kernel memory management for networking protocols
34.Sh SYNOPSIS
35.Fd #include <sys/mbuf.h>
36.Ft struct mbuf *
37.Fn m_copym2 "struct mbuf *m" "int off" "int len" "int wait"
38.Ft struct mbuf *
39.Fn m_copym "struct mbuf *m" "int off" "int len" "int wait"
40.Ft struct mbuf *
41.Fn m_free "struct mbuf *m"
42.Fn MFREE "struct mbuf *m" "struct mbuf *n"
43.Ft struct mbuf *
44.Fn m_get "int how" "int type"
45.Fn MGET "struct mbuf *m" "int how" "int type"
46.Ft struct mbuf *
47.Fn m_getclr "int how" "int type"
48.Ft struct mbuf *
49.Fn m_gethdr "int how" "int type"
50.Fn MGETHDR "struct mbuf *m" "int how" "int type"
51.Ft struct mbuf *
52.Fn m_prepend "struct mbuf *m" "int len" "int how"
53.Fn M_PREPEND "struct mbuf *m" "int plen" "int how"
54.Ft struct mbuf *
55.Fn m_pulldown "struct mbuf *m" "int off" "int len" "int *offp"
56.Ft struct mbuf *
57.Fn m_pullup "struct mbuf *n" "int len"
58.Ft struct mbuf *
59.Fn m_pullup2 "struct mbuf *n" "int len"
60.Ft struct mbuf *
61.Fn m_split "struct mbuf *m0" "int len0" "int wait"
62.Ft struct mbuf *
63.Fn m_inject "struct mbuf *m0" "int len0" "int siz" "int wait"
64.Ft struct mbuf *
65.Fn m_getptr "struct mbuf *m" "int loc" "int *off"
66.Ft void
67.Fn m_adj "struct mbuf *mp" "int req_len"
68.Ft void
69.Fn m_copyback "struct mbuf *m0" "int off" "int len" "caddr_t cp"
70.Ft void
71.Fn m_freem "struct mbuf *m"
72.Ft void
73.Fn m_reclaim "void"
74.Ft void
75.Fn m_copydata "struct mbuf *m" "int off" "int len" "caddr_t cp"
76.Ft void
77.Fn m_cat "struct mbuf *m" "struct mbuf *n"
78.Ft struct mbuf *
79.Fn m_devget "char *buf" "int totlen" "int off" "struct ifnet *ifp" \
80"void (*func)(const void *, void *, size_t)"
81.Ft void
82.Fn m_zero "struct mbuf *m"
83.Ft int
84.Fn m_apply "struct mbuf *m" "int off" "int len" \
85"int (*func)(caddr_t, caddr_t, unsigned int)" "caddr_t fstate"
86.Fn MCLGET "struct mbuf *m" "int how"
87.Fn MCLGETI "struct mbuf *m" "int how" "struct ifnet *ifp" "int len"
88.Fn MEXTADD "struct mbuf *m" "caddr_t buf" "u_int size" "int type" \
89"void (*free)(caddr_t, u_int, void *)" "void *arg"
90.Fn M_ALIGN "struct mbuf *m" "int len"
91.Fn MH_ALIGN "struct mbuf *m" "int len"
92.Fn M_READONLY "struct mbuf *m"
93.Fn M_LEADINGSPACE "struct mbuf *m"
94.Fn M_TRAILINGSPACE "struct mbuf *m"
95.Pp
96.Bd -literal
97#define MLEN            (MSIZE - sizeof(struct m_hdr))
98#define MHLEN           (MLEN - sizeof(struct pkthdr))
99
100#define MINCLSIZE       (MHLEN + MLEN + 1)
101#define M_MAXCOMPRESS   (MHLEN / 2)
102
103#define mtod(m,t)       ((t)((m)-\*(Gtm_data))
104
105struct m_hdr {
106        struct  mbuf *mh_next;
107        struct  mbuf *mh_nextpkt;
108        caddr_t mh_data;
109        u_int   mh_len;
110        short   mh_type;
111        u_short mh_flags;
112};
113
114struct pkthdr {
115        struct  ifnet *rcvif;
116        SLIST_HEAD(packet_tags, m_tag) tags;
117        int     len;
118        u_int16_t csum_flags;
119        u_int16_t ether_vtag;
120	struct	pkthdr_pf pf;
121};
122
123struct pkthdr_pf {
124	void	 *hdr;
125	u_int	  rtableid;
126	u_int32_t qid;
127	u_int16_t tag;
128	u_int8_t  flags;
129	u_int8_t  routed;
130};
131
132struct m_ext {
133        caddr_t ext_buf;
134        void    (*ext_free)(caddr_t, u_int, void *);
135        void    *ext_arg;
136        u_int   ext_size;
137        int     ext_type;
138        struct mbuf *ext_nextref;
139        struct mbuf *ext_prevref;
140};
141
142struct mbuf {
143        struct  m_hdr m_hdr;
144        union {
145                struct {
146                        struct  pkthdr MH_pkthdr;
147                        union {
148                                struct  m_ext MH_ext;
149                                char    MH_databuf[MHLEN];
150                        } MH_dat;
151                } MH;
152                char    M_databuf[MLEN];
153        } M_dat;
154};
155
156#define m_next          m_hdr.mh_next
157#define m_len           m_hdr.mh_len
158#define m_data          m_hdr.mh_data
159#define m_type          m_hdr.mh_type
160#define m_flags         m_hdr.mh_flags
161#define m_nextpkt       m_hdr.mh_nextpkt
162#define m_act           m_nextpkt
163#define m_pkthdr        M_dat.MH.MH_pkthdr
164#define m_ext           M_dat.MH.MH_dat.MH_ext
165#define m_pktdat        M_dat.MH.MH_dat.MH_databuf
166#define m_dat           M_dat.M_databuf
167.Ed
168.Sh DESCRIPTION
169The
170.Nm
171functions provide a way to manage the memory buffers used by the kernel's
172networking subsystem.
173Several functions and macros are used to allocate and deallocate mbufs,
174but also to get, inject, remove, copy, modify, prepend or append data
175inside these mbufs.
176The size of an
177.Nm
178is MSIZE
179.Pq defined in Aq Pa sys/param.h .
180.Pp
181An
182.Nm
183structure is defined as an
184.Fa m_hdr
185structure followed by a
186union.
187The header contains the following elements:
188.Bl -tag -width foobarmoocow
189.It Fa mh_next
190A pointer to the next mbuf in the mbuf chain.
191.It Fa mh_nextpkt
192A pointer to the next mbuf chain (i.e., packet) in the queue.
193.It Fa mh_data
194Indicates the address of the beginning of data in the mbuf.
195.It Fa mh_len
196Indicates the amount of data in the mbuf.
197.It Fa mh_type
198Indicates the type of data contained in the mbuf (see below).
199.It Fa mh_flags
200Flags (see below).
201.El
202.Pp
203The
204.Fa mh_type
205variable can take the following values:
206.Pp
207.Bl -tag -compact -offset indent -width XXXXXXXXXXXXXXXXXX
208.It Dv MT_FREE
209the mbuf should be on the free list.
210.It Dv MT_DATA
211the data in the mbuf was dynamically allocated.
212.It Dv MT_HEADER
213the data contains a packet header.
214.It Dv MT_SONAME
215the data is a socket name.
216.It Dv MT_SOOPTS
217the data are socket options.
218.It Dv MT_FTABLE
219the data is a fragment reassembly header.
220.It Dv MT_CONTROL
221the mbuf contains extra-data protocol message.
222.It Dv MT_OOBDATA
223the data consists of out-of-banddata.
224.El
225.Pp
226The
227.Fa mh_flags
228variable can take the following values:
229.Pp
230.Bl -tag -compact -offset indent -width XXXXXXXXXXXXXXXXXX
231.It Dv M_EXT
232mbuf has associated external storage.
233.It Dv M_PKTHDR
234the mbuf is the first that forms a packet.
235.It Dv M_EOR
236end of record.
237.It Dv M_CLUSTER
238the external storage is a cluster.
239.It Dv M_PROTO1
240protocol-specific.
241.It Dv M_BCAST
242packet send/received as link-level broadcast.
243.It Dv M_MCAST
244packet send/received as link-level multicast.
245.It Dv M_CONF
246packet was encrypted (ESP-transport).
247.It Dv M_AUTH
248packet was authenticated (AH or ESP).
249.It Dv M_AUTH_AH
250header was authenticated (AH).
251.It Dv M_TUNNEL
252header was IP-in-IP encapsulated by tunnel mode IPsec.
253.It Dv M_LINK0
254link layer specific flag.
255.It Dv M_LOOP
256for mbuf statistics.
257.It Dv M_FILDROP
258dropped by
259.Xr bpf 4
260filter.
261.It Dv M_VLANTAG
262.Fa m_pkthdr.ether_vtag
263variable is valid.
264.El
265.Pp
266An external cluster is used when the data to hold in the mbuf is
267large.
268The size of an external cluster is MCLBYTES
269.Pq also defined in Aq Pa sys/param.h .
270A cluster should be used when the size of the data reach MINCLSIZE
271(the minimum size to be held by an external cluster).
272.Pp
273The combination of the M_EXT and M_PKTHDR flags give four types of
274mbuf.
275When none of these constants are in use, the mbuf is a "normal"
276one, where the data part of the mbuf has the following elements:
277.Bl -tag -width foobarmoocow
278.It Fa m_dat
279buffer holding the data (size MLEN).
280.El
281.Pp
282When only M_PKTHDR is set, the data contained in the mbuf is a packet header.
283The data itself is contained in the mbuf (just like the previous case),
284but part of the mbuf is used to store a packet header.
285The data part has then the following elements:
286.Bl -tag -width foobarmoocow
287.It Fa m_pkthdr
288packet header, containing the length of the data, a pointer to the
289interface on which the data was received, checksum information
290and list of
291.Xr mbuf_tags 9 .
292.It Fa m_pktdat
293buffer holding the data (size MHLEN).
294.El
295.Pp
296The
297.Fa m_pkthdr.csum
298variable can take the following values:
299.Pp
300.Bl -tag -compact -offset indent -width XXXXXXXXXXXXXXXXXX
301.It Dv M_IPV4_CSUM_OUT
302IPv4 checksum needed.
303.It Dv M_TCPV4_CSUM_OUT
304TCP checksum needed.
305.It Dv M_UDPV4_CSUM_OUT
306UDP checksum needed.
307.It Dv M_IPV4_CSUM_IN_OK
308IPv4 checksum verified.
309.It Dv M_IPV4_CSUM_IN_BAD
310IPv4 checksum bad.
311.It Dv M_TCP_CSUM_IN_OK
312TCP/IPv4 checksum verified.
313.It Dv M_TCP_CSUM_IN_BAD
314TCP/IPv4 checksum bad.
315.It Dv M_UDP_CSUM_IN_OK
316UDP/IPv4 checksum verified.
317.It Dv M_UDP_CSUM_IN_BAD
318UDP/IPv4 checksum bad.
319.El
320.Pp
321When only M_EXT flag is set, an external storage buffer is being used to
322hold the data, which is no longer stored in the mbuf.
323The data part of the mbuf has now the following elements:
324.Bl -tag -width foobarmoocow
325.It Fa m_pkthdr
326a packet header, just like the previous case, but it is empty.
327No information is stored here
328.It Fa m_ext
329a structure containing information about the external storage
330buffer.
331The information consists of the address of the external buffer,
332a pointer to the function used to free the buffer, a pointer to the
333arguments of the function, the size of the buffer, the type of the
334buffer, and pointers to the previous and next mbufs using this
335cluster.
336.El
337.Pp
338When both the M_EXT and M_PKTHDR flags are set, an external storage buffer
339is being used to store the data and this data contains a packet header.
340The structure used is the same as the previous one except that the
341.Fa m_pkthdr
342element is not empty, it contains the same information as when
343M_PKTHDR is used alone.
344.Bl -tag -width Ds
345.It Fn m_copym "struct mbuf *m" "int off" "int len" "int wait"
346Copy an mbuf chain starting at
347.Fa off
348bytes from the beginning
349and continuing for
350.Fa len
351bytes.
352If
353.Fa off
354is zero and
355.Fa m
356has the M_PKTHDR flag set,
357the header is copied.
358If
359.Fa len
360is M_COPYALL
361the whole mbuf is copied.
362The
363.Fa wait
364parameter can be M_WAIT or
365M_DONTWAIT.
366It does not copy clusters, it just increases their reference count.
367.It Fn m_copym2 "struct mbuf *m" "int off" "int len" "int wait"
368The same as
369.Fn m_copym
370except that it copies cluster mbufs, whereas
371.Fn m_copym
372just increases the reference count of the clusters.
373.It Fn m_free "struct mbuf *m"
374Free the mbuf pointed to by
375.Fa m .
376A pointer to the successor of the mbuf,
377if it exists, is returned by the function.
378.It Fn MFREE "struct mbuf *m" "struct mbuf *n"
379Free the mbuf pointed to by
380.Fa m
381and use
382.Fa n
383to point to the next mbuf in
384the chain if it exists.
385See
386.Fn m_free .
387.It Fn m_get "int how" "int type"
388Return a pointer to an mbuf of the type specified.
389If the
390.Fa how
391argument is
392.Fa M_WAITOK ,
393the function may call
394.Xr tsleep 9
395to await resources.
396If
397.Fa how
398is
399.Fa M_DONTWAIT
400and resources are not available,
401.Fn m_get
402returns NULL.
403.It Fn MGET "struct mbuf *m" "int how" "int type"
404Return a pointer to an mbuf in
405.Fa m
406of the type specified.
407See
408.Fn m_get
409for a description of
410.Fa how .
411.It Fn m_getclr "int how" "int type"
412Return a pointer to an mbuf of the type specified, and clear the data
413area of the mbuf.
414See
415.Fn m_get
416for a description of
417.Fa how .
418.It Fn m_gethdr "int how" "int type"
419Return a pointer to an mbuf of the type specified after initializing
420it to contain a packet header.
421See
422.Fn m_get
423for a description of
424.Fa how .
425.It Fn MGETHDR "struct mbuf *m" "int how" "int type"
426Return a pointer to an mbuf of the type specified after initializing
427it to contain a packet header.
428See
429.Fn m_get
430for a description of
431.Fa how .
432.It Fn m_prepend "struct mbuf *m" "int len" "int how"
433Allocate a new mbuf and prepend it to the mbuf chain pointed to by
434.Fa m .
435If
436.Fa m
437points to an mbuf with a packet header, it is moved to the new
438mbuf that has been prepended.
439The return value is a pointer on the new mbuf chain.
440If this function fails to allocate a new mbuf,
441.Fa m
442is freed.
443See
444.Fn m_get
445for a description of
446.Fa how .
447.Pp
448.Fn m_prepend
449should never be called directly.
450Use
451.Fn M_PREPEND
452instead.
453.It Fn M_PREPEND "struct mbuf *m" "int plen" "int how"
454Prepend space of size
455.Fa plen
456to the mbuf pointed to by
457.Fa m .
458If a new mbuf must be allocated,
459.Fa how
460specifies whether to wait or not.
461If this function fails to allocate a new mbuf,
462.Fa m
463is freed.
464.It Fn m_pulldown "struct mbuf *m" "int off" "int len" "int *offp"
465Ensure that the data in the mbuf chain starting at
466.Fa off
467and ending at
468.Fa off+len
469will be put in a continuous memory region.
470.Fa len
471must be smaller or equal than MCLBYTES.
472The pointer returned points to an mbuf in the chain and the new offset
473for data in this mbuf is
474.Fa *offp .
475If this function fails,
476.Fa m
477is freed.
478.It Fn m_pullup "struct mbuf *n" "int len"
479Ensure that the data in the mbuf chain starting at the beginning of
480the chain and ending at
481.Fa len
482will be put in continuous memory region.
483To avoid being called again,
484.Fn m_pullup
485will attempt to copy
486.Fa "max_protohdr - len"
487bytes into the first mbuf.
488The
489.Fa len
490argument must be smaller or equal than MHLEN.
491If this function fails,
492.Fa n
493is freed.
494.It Fn m_pullup2 "struct mbuf *n" "int len"
495Just like
496.Fn m_pullup ,
497ensure that the data starting at the beginning of the mbuf chain and
498ending at
499.Fa len
500will be put in continuous memory region.
501The
502.Fa len
503argument can be up to MCLBYTES.
504.Fn m_pullup2
505will simply call
506.Fn m_pullup
507if
508.Fa len
509is smaller or equal to MHLEN.
510.It Fn m_split "struct mbuf *m0" "int len0" "int wait"
511Split an mbuf chain in two pieces, returning a pointer to
512the tail (which is made of the previous mbuf chain except the first
513.Fa len0
514bytes).
515.It Fn m_inject "struct mbuf *m0" "int len0" "int siz" "int wait"
516Inject a new mbuf chain of length
517.Fa siz
518into the mbuf chain pointed to by
519.Fa m0
520at position
521.Fa len0 .
522If there is enough space for an object of size
523.Fa siz
524in the appropriate location, no memory will be allocated.
525On failure, the function returns NULL (the mbuf is left untouched) and
526on success, a pointer to the first injected mbuf is returned.
527.It Fn m_getptr "struct mbuf *m" "int loc" "int *off"
528Returns a pointer to the mbuf containing the data located at
529.Fa loc
530bytes of the beginning.
531The offset in the new mbuf is pointed to by
532.Fa off .
533.It Fn m_adj "struct mbuf *mp" "int req_len"
534Trims
535.Fa req_len
536bytes of data from the mbuf chain pointed to by
537.Fa mp .
538If
539.Fa req_len
540is positive, the data will be trimmed from the head of the mbuf chain
541and if it is negative, it will be trimmed from the tail of the mbuf
542chain.
543.It Fn m_copyback "struct mbuf *m0" "int off" "int len" "caddr_t cp"
544Copy data from a buffer pointed to by
545.Fa cp
546back into the mbuf chain pointed to by
547.Fa m0
548starting at
549.Fa off
550bytes from the beginning, extending the mbuf chain if
551necessary.
552The mbuf chain must be initialized properly, including setting
553.Fa m_len .
554.It Fn m_freem "struct mbuf *m"
555Free the mbuf chain pointed to by
556.Fa m .
557.It Fn m_reclaim "void"
558Ask protocols to free unused memory space.
559.It Fn m_copydata "struct mbuf *m" "int off" "int len" "caddr_t cp"
560Copy data from the mbuf chain pointed to by
561.Fa m
562starting at
563.Fa off
564bytes from the beginning and continuing for
565.Fa len
566bytes into the buffer pointed to by
567.Fa cp .
568.It Fn m_cat "struct mbuf *m" "struct mbuf *n"
569Concatenate the mbuf chain pointed to by
570.Fa n
571to the mbuf chain pointed to by
572.Fa m .
573The mbuf chains must be of the same type.
574.It Fn m_devget "char *buf" "int totlen" "int off" "struct ifnet *ifp" \
575"void (*func)(const void *, void *, size_t)"
576Copy
577.Fa totlen
578bytes of data from device local memory pointed to by
579.Fa buf
580using the function
581.Fa func
582or
583.Fn bcopy
584if
585.Fa func
586is NULL.
587The data is copied into an mbuf chain at offset
588.Fa off
589and a pointer to the head of the chain is returned.
590Returns NULL on failure.
591.It Fn m_zero "struct mbuf *m"
592Zeroize the data part of the mbufs in the mbuf chain pointed to by
593.Fa m .
594.It Fn m_apply "struct mbuf *m" "int off" "int len" \
595"int (*func)(caddr_t, caddr_t, unsigned int)" "caddr_t fstate"
596Apply the function
597.Fa func
598to the data in the mbuf chain pointed to by
599.Fa m
600starting at
601.Fa off
602bytes from the beginning and continuing for
603.Fa len
604bytes.
605.It Fn mtod "struct mbuf *m" "datatype"
606Return a pointer to the data contained in the specified mbuf
607.Fa m
608cast to
609.Fa datatype .
610.It Fn MCLGET "struct mbuf *m" "int how"
611Allocate and add an mbuf cluster to the mbuf pointed to by
612.Fa m .
613On success, the flag M_EXT is set in the mbuf.
614See
615.Fn m_get
616for a description of
617.Fa how .
618.It Fn MCLGETI "struct mbuf *m" "int how" "struct ifnet *ifp" "int len"
619If
620.Fa m
621is NULL, allocate it.
622Then allocate and add an mbuf cluster of length
623.Fa len
624to the mbuf pointed to by
625.Fa m .
626If
627.Fa ifp
628is passed in, then per-interface accounting for the mbuf will occur,
629and thus mbuf allocation can fail when limits are reached.
630Returns either the mbuf
631.Fa m
632that was passed in, or the newly allocated one which was allocated; in
633either case the flag M_EXT is set in the mbuf.
634See
635.Fn m_get
636for a description of
637.Fa how .
638.It Fn MEXTADD "struct mbuf *m" "caddr_t buf" "u_int size" "int type" \
639"void (*free)(caddr_t, u_int, void *)" "void *arg"
640Add pre-allocated storage to the mbuf pointed to by
641.Fa m .
642On success, the flag M_EXT is set in the mbuf.
643.It Fn M_ALIGN "struct mbuf *m" "int len"
644Set the
645.Fa m_data
646pointer of the newly allocated mbuf with
647.Fn m_get
648or
649.Fn MGET
650pointed to by
651.Fa m
652to an object of the specified size
653.Fa len
654at the end of the mbuf, longword aligned.
655.It Fn MH_ALIGN "m" "len"
656Same as
657.Fn M_ALIGN
658except it is for an mbuf allocated with
659.Fn m_gethdr
660or
661.Fn MGETHDR .
662.It Fn M_READONLY "struct mbuf *m"
663Check if the data of the mbuf pointed to by
664.Fa m
665is read-only.
666This is true for non-cluster external storage and for clusters that
667are being referenced by more than one mbuf.
668.It Fn M_LEADINGSPACE "struct mbuf *m"
669Compute the amount of space available before the current start of data
670in the mbuf pointed to by
671.Fa m .
672.It Fn M_TRAILINGSPACE "struct mbuf *m"
673Compute the amount of space available after the end of data in the
674mbuf pointed to by
675.El
676.Sh CODE REFERENCES
677The mbuf management functions are implemented in the files
678.Pa sys/kern/uipc_mbuf.c
679and
680.Pa sys/kern/uipc_mbuf2.c .
681The function prototypes and the macros are located in
682.Pa sys/sys/mbuf.h .
683.Sh SEE ALSO
684.Xr netstat 1 ,
685.Xr mbuf_tags 9
686.Pp
687"Networking Implementation Notes",
688.Pa /usr/share/doc/smm/18.net .
689.Rs
690.%A Jun-Ichiro Hagino
691.%T "Mbuf issues in 4.4BSD IPv6/IPsec support (experiences from KAME IPv6/IPsec implementation)"
692.%B "Proceedings of the Freenix Track: 2000 USENIX Annual Technical Conference"
693.%D June 2000
694.Re
695