mbuf.c revision 78189
178189Sbrian/*- 278189Sbrian * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org> 378189Sbrian * based on work by Toshiharu OHNO <tony-o@iij.ad.jp> 478189Sbrian * Internet Initiative Japan, Inc (IIJ) 578189Sbrian * All rights reserved. 66059Samurai * 778189Sbrian * Redistribution and use in source and binary forms, with or without 878189Sbrian * modification, are permitted provided that the following conditions 978189Sbrian * are met: 1078189Sbrian * 1. Redistributions of source code must retain the above copyright 1178189Sbrian * notice, this list of conditions and the following disclaimer. 1278189Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1378189Sbrian * notice, this list of conditions and the following disclaimer in the 1478189Sbrian * documentation and/or other materials provided with the distribution. 156059Samurai * 1678189Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1778189Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1878189Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1978189Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2078189Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2178189Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2278189Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2378189Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2478189Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2578189Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2678189Sbrian * SUCH DAMAGE. 276059Samurai * 2850479Speter * $FreeBSD: head/usr.sbin/ppp/mbuf.c 78189 2001-06-13 21:52:19Z brian $ 296059Samurai */ 3078189Sbrian 3136285Sbrian#include <sys/types.h> 3230715Sbrian 3330715Sbrian#include <stdio.h> 3430715Sbrian#include <stdlib.h> 3530715Sbrian#include <string.h> 3636285Sbrian#include <sysexits.h> 3736285Sbrian#include <termios.h> 3830715Sbrian 3937009Sbrian#include "defs.h" 4031343Sbrian#include "command.h" 4130715Sbrian#include "mbuf.h" 4230715Sbrian#include "log.h" 4336285Sbrian#include "descriptor.h" 4436285Sbrian#include "prompt.h" 4536285Sbrian#include "main.h" 466059Samurai 4754913Sbrian#define BUCKET_CHUNK 20 4854913Sbrian#define BUCKET_HASH 256 4954913Sbrian 5054913Sbrianstruct mbucket; 5154913Sbrian 5254913Sbrianstruct mfree { 5354913Sbrian struct mbucket *next; 5454913Sbrian size_t count; 5554913Sbrian}; 5654913Sbrian 5754913Sbrianstatic struct mbucket { 5854913Sbrian union { 5954913Sbrian struct mbuf m; 6054913Sbrian struct mfree f; 6154913Sbrian } u; 6254913Sbrian} *bucket[(M_MAXLEN + sizeof(struct mbuf)) / BUCKET_HASH]; 6354913Sbrian 6454913Sbrian#define M_BINDEX(sz) (((sz) + sizeof(struct mbuf) - 1) / BUCKET_HASH) 6554913Sbrian#define M_BUCKET(sz) (bucket + M_BINDEX(sz)) 6654913Sbrian#define M_ROUNDUP(sz) ((M_BINDEX(sz) + 1) * BUCKET_HASH) 6754913Sbrian 6832663Sbrianstatic struct memmap { 696059Samurai struct mbuf *queue; 7054912Sbrian size_t fragments; 7154912Sbrian size_t octets; 7247695Sbrian} MemMap[MB_MAX + 1]; 736059Samurai 7446686Sbrianstatic unsigned long long mbuf_Mallocs, mbuf_Frees; 756059Samurai 766059Samuraiint 7754912Sbrianm_length(struct mbuf *bp) 786059Samurai{ 796059Samurai int len; 806059Samurai 8154912Sbrian for (len = 0; bp; bp = bp->m_next) 8254912Sbrian len += bp->m_len; 8346828Sbrian return len; 846059Samurai} 856059Samurai 8667911Sbrianstatic const char * 8767680Sbrianmbuftype(int type) 8867680Sbrian{ 8967680Sbrian static const char * const mbufdesc[MB_MAX] = { 9067680Sbrian "ip in", "ip out", "nat in", "nat out", "mp in", "mp out", 9167680Sbrian "vj in", "vj out", "icompd in", "icompd out", "compd in", "compd out", 9267680Sbrian "lqr in", "lqr out", "echo in", "echo out", "proto in", "proto out", 9367680Sbrian "acf in", "acf out", "sync in", "sync out", "hdlc in", "hdlc out", 9467680Sbrian "async in", "async out", "cbcp in", "cbcp out", "chap in", "chap out", 9567680Sbrian "pap in", "pap out", "ccp in", "ccp out", "ipcp in", "ipcp out", 9667680Sbrian "lcp in", "lcp out" 9767680Sbrian }; 9867680Sbrian 9967680Sbrian return type < 0 || type >= MB_MAX ? "unknown" : mbufdesc[type]; 10067680Sbrian} 10167680Sbrian 1026059Samuraistruct mbuf * 10354912Sbrianm_get(size_t m_len, int type) 1046059Samurai{ 10554913Sbrian struct mbucket **mb; 1066059Samurai struct mbuf *bp; 10754913Sbrian size_t size; 1086059Samurai 10947695Sbrian if (type > MB_MAX) { 11036285Sbrian log_Printf(LogERROR, "Bad mbuf type %d\n", type); 11147695Sbrian type = MB_UNKNOWN; 11247695Sbrian } 11354913Sbrian 11454913Sbrian if (m_len > M_MAXLEN || m_len == 0) { 11567680Sbrian log_Printf(LogERROR, "Request for mbuf size %lu (\"%s\") denied !\n", 11667680Sbrian (u_long)m_len, mbuftype(type)); 11736285Sbrian AbortProgram(EX_OSERR); 11825630Sbrian } 11954913Sbrian 12054913Sbrian mb = M_BUCKET(m_len); 12154913Sbrian size = M_ROUNDUP(m_len); 12254913Sbrian 12354913Sbrian if (*mb) { 12454913Sbrian /* We've got some free blocks of the right size */ 12554913Sbrian bp = &(*mb)->u.m; 12654913Sbrian if (--(*mb)->u.f.count == 0) 12754913Sbrian *mb = (*mb)->u.f.next; 12854913Sbrian else { 12954913Sbrian ((struct mbucket *)((char *)*mb + size))->u.f.count = (*mb)->u.f.count; 13054913Sbrian *mb = (struct mbucket *)((char *)*mb + size); 13154913Sbrian (*mb)->u.f.next = NULL; 13254913Sbrian } 13354913Sbrian } else { 13454913Sbrian /* 13554913Sbrian * Allocate another chunk of mbufs, use the first and put the rest on 13654913Sbrian * the free list 13754913Sbrian */ 13854913Sbrian *mb = (struct mbucket *)malloc(BUCKET_CHUNK * size); 13954913Sbrian if (*mb == NULL) { 14058042Sbrian log_Printf(LogALERT, "Failed to allocate memory (%lu)\n", 14158042Sbrian (unsigned long)BUCKET_CHUNK * size); 14254913Sbrian AbortProgram(EX_OSERR); 14354913Sbrian } 14454913Sbrian bp = &(*mb)->u.m; 14554913Sbrian *mb = (struct mbucket *)((char *)*mb + size); 14654913Sbrian (*mb)->u.f.count = BUCKET_CHUNK - 1; 14754913Sbrian (*mb)->u.f.next = NULL; 14854913Sbrian } 14954913Sbrian 15046686Sbrian mbuf_Mallocs++; 15154913Sbrian 15230715Sbrian memset(bp, '\0', sizeof(struct mbuf)); 15354913Sbrian bp->m_size = size - sizeof *bp; 15454913Sbrian bp->m_len = m_len; 15554913Sbrian bp->m_type = type; 15654913Sbrian 15738471Sbrian MemMap[type].fragments++; 15854913Sbrian MemMap[type].octets += bp->m_size; 15954913Sbrian 16045103Sbrian return bp; 1616059Samurai} 1626059Samurai 1636059Samuraistruct mbuf * 16454912Sbrianm_free(struct mbuf *bp) 1656059Samurai{ 16654913Sbrian struct mbucket **mb, *f; 1676059Samurai struct mbuf *nbp; 1686059Samurai 16954913Sbrian if ((f = (struct mbucket *)bp) != NULL) { 17054912Sbrian MemMap[bp->m_type].fragments--; 17154912Sbrian MemMap[bp->m_type].octets -= bp->m_size; 17254913Sbrian 17354913Sbrian nbp = bp->m_next; 17454913Sbrian mb = M_BUCKET(bp->m_size); 17554913Sbrian f->u.f.next = *mb; 17654913Sbrian f->u.f.count = 1; 17754913Sbrian *mb = f; 17854913Sbrian 17946686Sbrian mbuf_Frees++; 18045103Sbrian bp = nbp; 1816059Samurai } 18245103Sbrian 18345103Sbrian return bp; 1846059Samurai} 1856059Samurai 1866059Samuraivoid 18754912Sbrianm_freem(struct mbuf *bp) 1886059Samurai{ 1896059Samurai while (bp) 19054912Sbrian bp = m_free(bp); 1916059Samurai} 1926059Samurai 1936059Samuraistruct mbuf * 19446686Sbrianmbuf_Read(struct mbuf *bp, void *v, size_t len) 1956059Samurai{ 1966059Samurai int nb; 19746686Sbrian u_char *ptr = v; 1986059Samurai 1996059Samurai while (bp && len > 0) { 20054912Sbrian if (len > bp->m_len) 20154912Sbrian nb = bp->m_len; 2026059Samurai else 2036059Samurai nb = len; 20446686Sbrian if (nb) { 20546686Sbrian memcpy(ptr, MBUF_CTOP(bp), nb); 20646686Sbrian ptr += nb; 20754912Sbrian bp->m_len -= nb; 20846686Sbrian len -= nb; 20954912Sbrian bp->m_offset += nb; 21046686Sbrian } 21154912Sbrian if (bp->m_len == 0) 21254912Sbrian bp = m_free(bp); 2136059Samurai } 21446686Sbrian 21554912Sbrian while (bp && bp->m_len == 0) 21654912Sbrian bp = m_free(bp); 21746686Sbrian 21846686Sbrian return bp; 2196059Samurai} 2208857Srgrimes 22146686Sbriansize_t 22246686Sbrianmbuf_View(struct mbuf *bp, void *v, size_t len) 22346686Sbrian{ 22446686Sbrian size_t nb, l = len; 22546686Sbrian u_char *ptr = v; 22646686Sbrian 22746686Sbrian while (bp && l > 0) { 22854912Sbrian if (l > bp->m_len) 22954912Sbrian nb = bp->m_len; 23046686Sbrian else 23146686Sbrian nb = l; 23246686Sbrian memcpy(ptr, MBUF_CTOP(bp), nb); 23346686Sbrian ptr += nb; 23446686Sbrian l -= nb; 23554912Sbrian bp = bp->m_next; 23646686Sbrian } 23746686Sbrian 23846686Sbrian return len - l; 23946686Sbrian} 24046686Sbrian 24146686Sbrianstruct mbuf * 24254912Sbrianm_prepend(struct mbuf *bp, const void *ptr, size_t len, size_t extra) 24346686Sbrian{ 24446686Sbrian struct mbuf *head; 24546686Sbrian 24654912Sbrian if (bp && bp->m_offset) { 24754912Sbrian if (bp->m_offset >= len) { 24854912Sbrian bp->m_offset -= len; 24954912Sbrian bp->m_len += len; 25046686Sbrian memcpy(MBUF_CTOP(bp), ptr, len); 25146686Sbrian return bp; 25246686Sbrian } 25354912Sbrian len -= bp->m_offset; 25454912Sbrian memcpy(bp + 1, (const char *)ptr + len, bp->m_offset); 25554912Sbrian bp->m_len += bp->m_offset; 25654912Sbrian bp->m_offset = 0; 25746686Sbrian } 25846686Sbrian 25954912Sbrian head = m_get(len + extra, bp ? bp->m_type : MB_UNKNOWN); 26054912Sbrian head->m_offset = extra; 26154912Sbrian head->m_len -= extra; 26255353Sbrian if (ptr) 26355353Sbrian memcpy(MBUF_CTOP(head), ptr, len); 26454912Sbrian head->m_next = bp; 26546686Sbrian 26646686Sbrian return head; 26746686Sbrian} 26846686Sbrian 26946686Sbrianstruct mbuf * 27054912Sbrianm_adj(struct mbuf *bp, ssize_t n) 27146686Sbrian{ 27254912Sbrian if (n > 0) { 27354912Sbrian while (bp) { 27454912Sbrian if (n < bp->m_len) { 27554912Sbrian bp->m_len = n; 27654912Sbrian bp->m_offset += n; 27754912Sbrian return bp; 27854912Sbrian } 27954912Sbrian n -= bp->m_len; 28054912Sbrian bp = m_free(bp); 28154912Sbrian } 28254912Sbrian } else { 28354912Sbrian if ((n = m_length(bp) + n) <= 0) { 28454912Sbrian m_freem(bp); 28554912Sbrian return NULL; 28654912Sbrian } 28754912Sbrian for (; bp; bp = bp->m_next, n -= bp->m_len) 28854912Sbrian if (n < bp->m_len) { 28954912Sbrian bp->m_len = n; 29054912Sbrian m_freem(bp->m_next); 29154912Sbrian bp->m_next = NULL; 29254912Sbrian break; 29354912Sbrian } 29446686Sbrian } 29546686Sbrian 29646686Sbrian return bp; 29746686Sbrian} 29846686Sbrian 2996059Samuraivoid 30054912Sbrianmbuf_Write(struct mbuf *bp, const void *ptr, size_t m_len) 3016059Samurai{ 3026059Samurai int plen; 3036059Samurai int nb; 3046059Samurai 30554912Sbrian plen = m_length(bp); 30654912Sbrian if (plen < m_len) 30754912Sbrian m_len = plen; 3086059Samurai 30954912Sbrian while (m_len > 0) { 31054912Sbrian nb = (m_len < bp->m_len) ? m_len : bp->m_len; 31130715Sbrian memcpy(MBUF_CTOP(bp), ptr, nb); 31254912Sbrian m_len -= bp->m_len; 31354912Sbrian bp = bp->m_next; 3146059Samurai } 3156059Samurai} 3166059Samurai 3176059Samuraiint 31836285Sbrianmbuf_Show(struct cmdargs const *arg) 3196059Samurai{ 3206059Samurai int i; 3216059Samurai 32238471Sbrian prompt_Printf(arg->prompt, "Fragments (octets) in use:\n"); 32347695Sbrian for (i = 0; i < MB_MAX; i += 2) 32454912Sbrian prompt_Printf(arg->prompt, "%10.10s: %04lu (%06lu)\t" 32554912Sbrian "%10.10s: %04lu (%06lu)\n", 32667680Sbrian mbuftype(i), (u_long)MemMap[i].fragments, 32767680Sbrian (u_long)MemMap[i].octets, mbuftype(i+1), 32854912Sbrian (u_long)MemMap[i+1].fragments, (u_long)MemMap[i+1].octets); 32926516Sbrian 33036285Sbrian if (i == MB_MAX) 33154912Sbrian prompt_Printf(arg->prompt, "%10.10s: %04lu (%06lu)\n", 33267680Sbrian mbuftype(i), (u_long)MemMap[i].fragments, 33354912Sbrian (u_long)MemMap[i].octets); 33426516Sbrian 33549582Sbrian prompt_Printf(arg->prompt, "Mallocs: %llu, Frees: %llu\n", 33646686Sbrian mbuf_Mallocs, mbuf_Frees); 33746686Sbrian 33826516Sbrian return 0; 3396059Samurai} 3406059Samurai 34136285Sbrianstruct mbuf * 34254912Sbrianm_dequeue(struct mqueue *q) 34336285Sbrian{ 34436285Sbrian struct mbuf *bp; 34536285Sbrian 34654912Sbrian log_Printf(LogDEBUG, "m_dequeue: queue len = %lu\n", (u_long)q->len); 34736285Sbrian bp = q->top; 34836285Sbrian if (bp) { 34954912Sbrian q->top = q->top->m_nextpkt; 35054912Sbrian q->len--; 35136285Sbrian if (q->top == NULL) { 35236285Sbrian q->last = q->top; 35354912Sbrian if (q->len) 35454912Sbrian log_Printf(LogERROR, "m_dequeue: Not zero (%lu)!!!\n", 35554912Sbrian (u_long)q->len); 35636285Sbrian } 35754912Sbrian bp->m_nextpkt = NULL; 35836285Sbrian } 35936285Sbrian 36036285Sbrian return bp; 36136285Sbrian} 36236285Sbrian 36336285Sbrianvoid 36454912Sbrianm_enqueue(struct mqueue *queue, struct mbuf *bp) 36536285Sbrian{ 36646828Sbrian if (bp != NULL) { 36746828Sbrian if (queue->last) { 36854912Sbrian queue->last->m_nextpkt = bp; 36946828Sbrian queue->last = bp; 37046828Sbrian } else 37146828Sbrian queue->last = queue->top = bp; 37254912Sbrian queue->len++; 37358042Sbrian log_Printf(LogDEBUG, "m_enqueue: len = %lu\n", (unsigned long)queue->len); 37446828Sbrian } 37536285Sbrian} 37645103Sbrian 37745103Sbrianstruct mbuf * 37854912Sbrianm_pullup(struct mbuf *bp) 37945103Sbrian{ 38045103Sbrian /* Put it all in one contigous (aligned) mbuf */ 38145103Sbrian 38246828Sbrian if (bp != NULL) { 38354912Sbrian if (bp->m_next != NULL) { 38446828Sbrian struct mbuf *nbp; 38546828Sbrian u_char *cp; 38645103Sbrian 38754912Sbrian nbp = m_get(m_length(bp), bp->m_type); 38845103Sbrian 38954912Sbrian for (cp = MBUF_CTOP(nbp); bp; bp = m_free(bp)) { 39054912Sbrian memcpy(cp, MBUF_CTOP(bp), bp->m_len); 39154912Sbrian cp += bp->m_len; 39246828Sbrian } 39346828Sbrian bp = nbp; 39445103Sbrian } 39545103Sbrian#ifndef __i386__ /* Do any other archs not care about alignment ? */ 39654912Sbrian else if ((bp->m_offset & (sizeof(long) - 1)) != 0) { 39754912Sbrian bcopy(MBUF_CTOP(bp), bp + 1, bp->m_len); 39854912Sbrian bp->m_offset = 0; 39946828Sbrian } 40046828Sbrian#endif 40145103Sbrian } 40245103Sbrian 40345103Sbrian return bp; 40445103Sbrian} 40547695Sbrian 40647695Sbrianvoid 40754912Sbrianm_settype(struct mbuf *bp, int type) 40847695Sbrian{ 40954912Sbrian for (; bp; bp = bp->m_next) 41054912Sbrian if (type != bp->m_type) { 41154912Sbrian MemMap[bp->m_type].fragments--; 41254912Sbrian MemMap[bp->m_type].octets -= bp->m_size; 41354912Sbrian bp->m_type = type; 41447695Sbrian MemMap[type].fragments++; 41554912Sbrian MemMap[type].octets += bp->m_size; 41647695Sbrian } 41747695Sbrian} 41855353Sbrian 41955353Sbrianstruct mbuf * 42060135Sbrianm_append(struct mbuf *bp, const void *v, size_t sz) 42155353Sbrian{ 42260135Sbrian struct mbuf *m = bp; 42360135Sbrian 42455353Sbrian if (m) { 42555353Sbrian while (m->m_next) 42655353Sbrian m = m->m_next; 42755353Sbrian if (m->m_size - m->m_len > sz) 42855353Sbrian m->m_len += sz; 42955353Sbrian else 43055353Sbrian m->m_next = m_prepend(NULL, v, sz, 0); 43155353Sbrian } else 43260135Sbrian bp = m_prepend(NULL, v, sz, 0); 43355353Sbrian 43460135Sbrian return bp; 43555353Sbrian} 436