Use dynamic memory allocation instead of mbuf's for multicast routing

state.

Note: this requires a recompilation of netstat (but netstat has been
broken since rev 1.52 of ip_mroute.c anyway)

Obtained from:	Significantly based on Steve McCanne's
		<mccanne@cs.berkeley.edu> work for BSD/OS
This commit is contained in:
Bill Fenner 1999-01-18 02:06:59 +00:00
parent 9bb02c7b92
commit 01b7c0826f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=42777
2 changed files with 86 additions and 103 deletions

View File

@ -9,13 +9,14 @@
* Modified by Bill Fenner, PARC, April 1995
*
* MROUTING Revision: 3.5
* $Id: ip_mroute.c,v 1.51 1998/12/16 18:07:11 fenner Exp $
* $Id: ip_mroute.c,v 1.52 1999/01/12 12:16:50 eivind Exp $
*/
#include "opt_mrouting.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
@ -185,7 +186,7 @@ ip_rsvp_force_done(so)
#define same(a1, a2) \
(bcmp((caddr_t)(a1), (caddr_t)(a2), INSIZ) == 0)
#define MT_MRTABLE MT_RTABLE /* since nothing else uses it */
static MALLOC_DEFINE(M_MRTABLE, "mroutetbl", "multicast routing tables");
/*
* Globals. All but ip_mrouter and ip_mrtproto could be static,
@ -203,7 +204,7 @@ static int ip_mrtproto;
#define NO_RTE_FOUND 0x1
#define RTE_FOUND 0x2
static struct mbuf *mfctable[MFCTBLSIZ];
static struct mfc *mfctable[MFCTBLSIZ];
static u_char nexpire[MFCTBLSIZ];
static struct vif viftable[MAXVIFS];
static u_int mrtdebug = 0; /* debug level */
@ -321,19 +322,17 @@ static int pim_assert;
*/
#define MFCFIND(o, g, rt) { \
register struct mbuf *_mb_rt = mfctable[MFCHASH(o,g)]; \
register struct mfc *_rt = NULL; \
register struct mfc *_rt = mfctable[MFCHASH(o,g)]; \
rt = NULL; \
++mrtstat.mrts_mfc_lookups; \
while (_mb_rt) { \
_rt = mtod(_mb_rt, struct mfc *); \
while (_rt) { \
if ((_rt->mfc_origin.s_addr == o) && \
(_rt->mfc_mcastgrp.s_addr == g) && \
(_mb_rt->m_act == NULL)) { \
(_rt->mfc_stall == NULL)) { \
rt = _rt; \
break; \
} \
_mb_rt = _mb_rt->m_next; \
_rt = _rt->mfc_next; \
} \
if (rt == NULL) { \
++mrtstat.mrts_mfc_misses; \
@ -591,8 +590,7 @@ X_ip_mrouter_done()
int i;
struct ifnet *ifp;
struct ifreq ifr;
struct mbuf *mb_rt;
struct mbuf *m;
struct mfc *rt;
struct rtdetq *rte;
int s;
@ -623,18 +621,18 @@ X_ip_mrouter_done()
* Free all multicast forwarding cache entries.
*/
for (i = 0; i < MFCTBLSIZ; i++) {
mb_rt = mfctable[i];
while (mb_rt) {
if (mb_rt->m_act != NULL) {
while (mb_rt->m_act) {
m = mb_rt->m_act;
mb_rt->m_act = m->m_act;
rte = mtod(m, struct rtdetq *);
m_freem(rte->m);
m_free(m);
}
for (rt = mfctable[i]; rt != NULL; ) {
struct mfc *nr = rt->mfc_next;
for (rte = rt->mfc_stall; rte != NULL; ) {
struct rtdetq *n = rte->next;
m_freem(rte->m);
free(rte, M_MRTABLE);
rte = n;
}
mb_rt = m_free(mb_rt);
free(rt, M_MRTABLE);
rt = nr;
}
}
@ -840,9 +838,7 @@ add_mfc(mfccp)
struct mfcctl *mfccp;
{
struct mfc *rt;
register struct mbuf *mb_rt;
u_long hash;
struct mbuf *mb_ntry;
struct rtdetq *rte;
register u_short nstl;
int s;
@ -871,25 +867,24 @@ add_mfc(mfccp)
*/
s = splnet();
hash = MFCHASH(mfccp->mfcc_origin.s_addr, mfccp->mfcc_mcastgrp.s_addr);
for (mb_rt = mfctable[hash], nstl = 0; mb_rt; mb_rt = mb_rt->m_next) {
for (rt = mfctable[hash], nstl = 0; rt; rt = rt->mfc_next) {
rt = mtod(mb_rt, struct mfc *);
if ((rt->mfc_origin.s_addr == mfccp->mfcc_origin.s_addr) &&
(rt->mfc_mcastgrp.s_addr == mfccp->mfcc_mcastgrp.s_addr) &&
(mb_rt->m_act != NULL)) {
(rt->mfc_stall != NULL)) {
if (nstl++)
log(LOG_ERR, "add_mfc %s o %lx g %lx p %x dbx %p\n",
"multiple kernel entries",
(u_long)ntohl(mfccp->mfcc_origin.s_addr),
(u_long)ntohl(mfccp->mfcc_mcastgrp.s_addr),
mfccp->mfcc_parent, (void *)mb_rt->m_act);
mfccp->mfcc_parent, (void *)rt->mfc_stall);
if (mrtdebug & DEBUG_MFC)
log(LOG_DEBUG,"add_mfc o %lx g %lx p %x dbg %p\n",
(u_long)ntohl(mfccp->mfcc_origin.s_addr),
(u_long)ntohl(mfccp->mfcc_mcastgrp.s_addr),
mfccp->mfcc_parent, (void *)mb_rt->m_act);
mfccp->mfcc_parent, (void *)rt->mfc_stall);
rt->mfc_origin = mfccp->mfcc_origin;
rt->mfc_mcastgrp = mfccp->mfcc_mcastgrp;
@ -906,19 +901,18 @@ add_mfc(mfccp)
nexpire[hash]--;
/* free packets Qed at the end of this entry */
while (mb_rt->m_act) {
mb_ntry = mb_rt->m_act;
rte = mtod(mb_ntry, struct rtdetq *);
/* #ifdef RSVP_ISI */
for (rte = rt->mfc_stall; rte != NULL; ) {
struct rtdetq *n = rte->next;
ip_mdq(rte->m, rte->ifp, rt, -1);
/* #endif */
mb_rt->m_act = mb_ntry->m_act;
m_freem(rte->m);
#ifdef UPCALL_TIMING
collate(&(rte->t));
#endif /* UPCALL_TIMING */
m_free(mb_ntry);
free(rte, M_MRTABLE);
rte = n;
}
rt->mfc_stall = NULL;
}
}
@ -932,9 +926,8 @@ add_mfc(mfccp)
(u_long)ntohl(mfccp->mfcc_mcastgrp.s_addr),
mfccp->mfcc_parent);
for (mb_rt = mfctable[hash]; mb_rt; mb_rt = mb_rt->m_next) {
for (rt = mfctable[hash]; rt != NULL; rt = rt->mfc_next) {
rt = mtod(mb_rt, struct mfc *);
if ((rt->mfc_origin.s_addr == mfccp->mfcc_origin.s_addr) &&
(rt->mfc_mcastgrp.s_addr == mfccp->mfcc_mcastgrp.s_addr)) {
@ -953,16 +946,14 @@ add_mfc(mfccp)
rt->mfc_expire = 0;
}
}
if (mb_rt == NULL) {
if (rt == NULL) {
/* no upcall, so make a new entry */
MGET(mb_rt, M_DONTWAIT, MT_MRTABLE);
if (mb_rt == NULL) {
rt = (struct mfc *)malloc(sizeof(*rt), M_MRTABLE, M_NOWAIT);
if (rt == NULL) {
splx(s);
return ENOBUFS;
}
rt = mtod(mb_rt, struct mfc *);
/* insert new entry at head of hash chain */
rt->mfc_origin = mfccp->mfcc_origin;
rt->mfc_mcastgrp = mfccp->mfcc_mcastgrp;
@ -975,11 +966,11 @@ add_mfc(mfccp)
rt->mfc_wrong_if = 0;
rt->mfc_last_assert.tv_sec = rt->mfc_last_assert.tv_usec = 0;
rt->mfc_expire = 0;
rt->mfc_stall = NULL;
/* link into table */
mb_rt->m_next = mfctable[hash];
mfctable[hash] = mb_rt;
mb_rt->m_act = NULL;
rt->mfc_next = mfctable[hash];
mfctable[hash] = rt;
}
}
splx(s);
@ -1022,8 +1013,7 @@ del_mfc(mfccp)
struct in_addr origin;
struct in_addr mcastgrp;
struct mfc *rt;
struct mbuf *mb_rt;
struct mbuf **nptr;
struct mfc **nptr;
u_long hash;
int s;
@ -1038,21 +1028,21 @@ del_mfc(mfccp)
s = splnet();
nptr = &mfctable[hash];
while ((mb_rt = *nptr) != NULL) {
rt = mtod(mb_rt, struct mfc *);
while ((rt = *nptr) != NULL) {
if (origin.s_addr == rt->mfc_origin.s_addr &&
mcastgrp.s_addr == rt->mfc_mcastgrp.s_addr &&
mb_rt->m_act == NULL)
rt->mfc_stall == NULL)
break;
nptr = &mb_rt->m_next;
nptr = &rt->mfc_next;
}
if (mb_rt == NULL) {
if (rt == NULL) {
splx(s);
return EADDRNOTAVAIL;
}
MFREE(mb_rt, *nptr);
*nptr = rt->mfc_next;
free(rt, M_MRTABLE);
splx(s);
@ -1178,13 +1168,9 @@ X_ip_mforward(ip, ifp, m, imo)
* send message to routing daemon
*/
register struct mbuf *mb_rt;
register struct mbuf *mb_ntry;
register struct mbuf *mb0;
register struct rtdetq *rte;
register struct mbuf *rte_m;
register u_long hash;
register int npkts;
int hlen = ip->ip_hl << 2;
#ifdef UPCALL_TIMING
struct timeval tp;
@ -1203,8 +1189,8 @@ X_ip_mforward(ip, ifp, m, imo)
* just going to fail anyway. Make sure to pullup the header so
* that other people can't step on it.
*/
MGET(mb_ntry, M_DONTWAIT, MT_DATA);
if (mb_ntry == NULL) {
rte = (struct rtdetq *)malloc((sizeof *rte), M_MRTABLE, M_NOWAIT);
if (rte == NULL) {
splx(s);
return ENOBUFS;
}
@ -1212,29 +1198,28 @@ X_ip_mforward(ip, ifp, m, imo)
if (mb0 && (M_HASCL(mb0) || mb0->m_len < hlen))
mb0 = m_pullup(mb0, hlen);
if (mb0 == NULL) {
m_free(mb_ntry);
free(rte, M_MRTABLE);
splx(s);
return ENOBUFS;
}
/* is there an upcall waiting for this packet? */
hash = MFCHASH(ip->ip_src.s_addr, ip->ip_dst.s_addr);
for (mb_rt = mfctable[hash]; mb_rt; mb_rt = mb_rt->m_next) {
rt = mtod(mb_rt, struct mfc *);
for (rt = mfctable[hash]; rt; rt = rt->mfc_next) {
if ((ip->ip_src.s_addr == rt->mfc_origin.s_addr) &&
(ip->ip_dst.s_addr == rt->mfc_mcastgrp.s_addr) &&
(mb_rt->m_act != NULL))
(rt->mfc_stall != NULL))
break;
}
if (mb_rt == NULL) {
if (rt == NULL) {
int i;
struct igmpmsg *im;
/* no upcall, so make a new entry */
MGET(mb_rt, M_DONTWAIT, MT_MRTABLE);
if (mb_rt == NULL) {
m_free(mb_ntry);
rt = (struct mfc *)malloc(sizeof(*rt), M_MRTABLE, M_NOWAIT);
if (rt == NULL) {
free(rte, M_MRTABLE);
m_freem(mb0);
splx(s);
return ENOBUFS;
@ -1242,9 +1227,9 @@ X_ip_mforward(ip, ifp, m, imo)
/* Make a copy of the header to send to the user level process */
mm = m_copy(mb0, 0, hlen);
if (mm == NULL) {
m_free(mb_ntry);
free(rte, M_MRTABLE);
m_freem(mb0);
m_free(mb_rt);
free(rt, M_MRTABLE);
splx(s);
return ENOBUFS;
}
@ -1264,15 +1249,13 @@ X_ip_mforward(ip, ifp, m, imo)
if (socket_send(ip_mrouter, mm, &k_igmpsrc) < 0) {
log(LOG_WARNING, "ip_mforward: ip_mrouter socket queue full\n");
++mrtstat.mrts_upq_sockfull;
m_free(mb_ntry);
free(rte, M_MRTABLE);
m_freem(mb0);
m_free(mb_rt);
free(rt, M_MRTABLE);
splx(s);
return ENOBUFS;
}
rt = mtod(mb_rt, struct mfc *);
/* insert new entry at head of hash chain */
rt->mfc_origin.s_addr = ip->ip_src.s_addr;
rt->mfc_mcastgrp.s_addr = ip->ip_dst.s_addr;
@ -1283,36 +1266,36 @@ X_ip_mforward(ip, ifp, m, imo)
rt->mfc_parent = -1;
/* link into table */
mb_rt->m_next = mfctable[hash];
mfctable[hash] = mb_rt;
mb_rt->m_act = NULL;
rt->mfc_next = mfctable[hash];
mfctable[hash] = rt;
rt->mfc_stall = rte;
rte_m = mb_rt;
} else {
/* determine if q has overflowed */
for (rte_m = mb_rt, npkts = 0; rte_m->m_act; rte_m = rte_m->m_act)
int npkts = 0;
struct rtdetq **p;
for (p = &rt->mfc_stall; *p != NULL; p = &(*p)->next)
npkts++;
if (npkts > MAX_UPQ) {
mrtstat.mrts_upq_ovflw++;
m_free(mb_ntry);
free(rte, M_MRTABLE);
m_freem(mb0);
splx(s);
return 0;
}
}
mb_ntry->m_act = NULL;
rte = mtod(mb_ntry, struct rtdetq *);
/* Add this entry to the end of the queue */
*p = rte;
}
rte->m = mb0;
rte->ifp = ifp;
#ifdef UPCALL_TIMING
rte->t = tp;
#endif
/* Add this entry to the end of the queue */
rte_m->m_act = mb_ntry;
rte->next = NULL;
splx(s);
@ -1331,9 +1314,8 @@ int (*ip_mforward)(struct ip *, struct ifnet *, struct mbuf *,
static void
expire_upcalls(void *unused)
{
struct mbuf *mb_rt, *m, **nptr;
struct rtdetq *rte;
struct mfc *mfc;
struct mfc *mfc, **nptr;
int i;
int s;
@ -1342,15 +1324,13 @@ expire_upcalls(void *unused)
if (nexpire[i] == 0)
continue;
nptr = &mfctable[i];
for (mb_rt = *nptr; mb_rt != NULL; mb_rt = *nptr) {
mfc = mtod(mb_rt, struct mfc *);
for (mfc = *nptr; mfc != NULL; mfc = *nptr) {
/*
* Skip real cache entries
* Make sure it wasn't marked to not expire (shouldn't happen)
* If it expires now
*/
if (mb_rt->m_act != NULL &&
if (mfc->mfc_stall != NULL &&
mfc->mfc_expire != 0 &&
--mfc->mfc_expire == 0) {
if (mrtdebug & DEBUG_EXPIRE)
@ -1361,20 +1341,20 @@ expire_upcalls(void *unused)
* drop all the packets
* free the mbuf with the pkt, if, timing info
*/
while (mb_rt->m_act) {
m = mb_rt->m_act;
mb_rt->m_act = m->m_act;
rte = mtod(m, struct rtdetq *);
for (rte = mfc->mfc_stall; rte; ) {
struct rtdetq *n = rte->next;
m_freem(rte->m);
m_free(m);
free(rte, M_MRTABLE);
rte = n;
}
++mrtstat.mrts_cache_cleanups;
nexpire[i]--;
MFREE(mb_rt, *nptr);
*nptr = mfc->mfc_next;
free(mfc, M_MRTABLE);
} else {
nptr = &mb_rt->m_next;
nptr = &mfc->mfc_next;
}
}
}
@ -1555,7 +1535,7 @@ phyint_send(ip, vifp, m)
if (mb_copy == NULL)
return;
if (vifp->v_rate_limit <= 0)
if (vifp->v_rate_limit == 0)
tbf_send_packet(vifp, mb_copy);
else
tbf_control(vifp, mb_copy, mtod(mb_copy, struct ip *), ip->ip_len);
@ -1616,7 +1596,7 @@ encap_send(ip, vifp, m)
ip->ip_sum = in_cksum(mb_copy, ip->ip_hl << 2);
mb_copy->m_data -= sizeof(multicast_encap_iphdr);
if (vifp->v_rate_limit <= 0)
if (vifp->v_rate_limit == 0)
tbf_send_packet(vifp, mb_copy);
else
tbf_control(vifp, mb_copy, ip, ip_copy->ip_len);

View File

@ -35,7 +35,7 @@
* SUCH DAMAGE.
*
* @(#)ip_mroute.h 8.1 (Berkeley) 6/10/93
* $Id: ip_mroute.h,v 1.13 1997/02/22 09:41:35 peter Exp $
* $Id: ip_mroute.h,v 1.14 1998/08/23 03:07:14 wollman Exp $
*/
#ifndef _NETINET_IP_MROUTE_H_
@ -188,6 +188,8 @@ struct mfc {
u_long mfc_wrong_if; /* wrong if for src-grp */
int mfc_expire; /* time to clean entry up */
struct timeval mfc_last_assert; /* last time I sent an assert*/
struct rtdetq *mfc_stall; /* q of packets awaiting mfc */
struct mfc *mfc_next; /* next mfc entry */
};
/*
@ -216,6 +218,7 @@ struct rtdetq {
#ifdef UPCALL_TIMING
struct timeval t; /* Timestamp */
#endif /* UPCALL_TIMING */
struct rtdetq *next; /* Next in list of packets */
};
#define MFCTBLSIZ 256