📄 ip_mroute.c
字号:
ip_mrouter = so;
bzero((caddr_t)mfctable, sizeof(mfctable));
bzero((caddr_t)nexpire, sizeof(nexpire));
pim_assert = 0;
expire_upcalls_ch = timeout(expire_upcalls, (caddr_t)NULL, EXPIRE_TIMEOUT);
if (mrtdebug)
log(LOG_DEBUG, "ip_mrouter_init\n");
return 0;
}
/*
* Disable multicast routing
*/
static int
X_ip_mrouter_done()
{
vifi_t vifi;
int i;
struct ifnet *ifp;
struct ifreq ifr;
struct mfc *rt;
struct rtdetq *rte;
int s;
s = splnet();
/*
* For each phyint in use, disable promiscuous reception of all IP
* multicasts.
*/
for (vifi = 0; vifi < numvifs; vifi++) {
if (viftable[vifi].v_lcl_addr.s_addr != 0 &&
!(viftable[vifi].v_flags & VIFF_TUNNEL)) {
((struct sockaddr_in *)&(ifr.ifr_addr))->sin_family = AF_INET;
((struct sockaddr_in *)&(ifr.ifr_addr))->sin_addr.s_addr
= INADDR_ANY;
ifp = viftable[vifi].v_ifp;
if_allmulti(ifp, 0);
}
}
bzero((caddr_t)tbftable, sizeof(tbftable));
bzero((caddr_t)viftable, sizeof(viftable));
numvifs = 0;
pim_assert = 0;
untimeout(expire_upcalls, (caddr_t)NULL, expire_upcalls_ch);
/*
* Free all multicast forwarding cache entries.
*/
for (i = 0; i < MFCTBLSIZ; i++) {
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;
}
free(rt, M_MRTABLE);
rt = nr;
}
}
bzero((caddr_t)mfctable, sizeof(mfctable));
/*
* Reset de-encapsulation cache
*/
last_encap_src = 0;
last_encap_vif = NULL;
have_encap_tunnel = 0;
ip_mrouter = NULL;
splx(s);
if (mrtdebug)
log(LOG_DEBUG, "ip_mrouter_done\n");
return 0;
}
#ifndef MROUTE_LKM
int (*ip_mrouter_done)(void) = X_ip_mrouter_done;
#endif
/*
* Set PIM assert processing global
*/
static int
set_assert(i)
int i;
{
if ((i != 1) && (i != 0))
return EINVAL;
pim_assert = i;
return 0;
}
/*
* Add a vif to the vif table
*/
static int
add_vif(vifcp)
register struct vifctl *vifcp;
{
register struct vif *vifp = viftable + vifcp->vifc_vifi;
static struct sockaddr_in sin = {sizeof sin, AF_INET};
struct ifaddr *ifa;
struct ifnet *ifp;
int error, s;
struct tbf *v_tbf = tbftable + vifcp->vifc_vifi;
if (vifcp->vifc_vifi >= MAXVIFS) return EINVAL;
if (vifp->v_lcl_addr.s_addr != 0) return EADDRINUSE;
/* Find the interface with an address in AF_INET family */
sin.sin_addr = vifcp->vifc_lcl_addr;
ifa = ifa_ifwithaddr((struct sockaddr *)&sin);
if (ifa == 0) return EADDRNOTAVAIL;
ifp = ifa->ifa_ifp;
if (vifcp->vifc_flags & VIFF_TUNNEL) {
if ((vifcp->vifc_flags & VIFF_SRCRT) == 0) {
/*
* An encapsulating tunnel is wanted. Tell ipip_input() to
* start paying attention to encapsulated packets.
*/
if (have_encap_tunnel == 0) {
have_encap_tunnel = 1;
for (s = 0; s < MAXVIFS; ++s) {
multicast_decap_if[s].if_name = "mdecap";
multicast_decap_if[s].if_unit = s;
}
}
/*
* Set interface to fake encapsulator interface
*/
ifp = &multicast_decap_if[vifcp->vifc_vifi];
/*
* Prepare cached route entry
*/
bzero(&vifp->v_route, sizeof(vifp->v_route));
} else {
log(LOG_ERR, "source routed tunnels not supported\n");
return EOPNOTSUPP;
}
} else {
/* Make sure the interface supports multicast */
if ((ifp->if_flags & IFF_MULTICAST) == 0)
return EOPNOTSUPP;
/* Enable promiscuous reception of all IP multicasts from the if */
s = splnet();
error = if_allmulti(ifp, 1);
splx(s);
if (error)
return error;
}
s = splnet();
/* define parameters for the tbf structure */
vifp->v_tbf = v_tbf;
GET_TIME(vifp->v_tbf->tbf_last_pkt_t);
vifp->v_tbf->tbf_n_tok = 0;
vifp->v_tbf->tbf_q_len = 0;
vifp->v_tbf->tbf_max_q_len = MAXQSIZE;
vifp->v_tbf->tbf_q = vifp->v_tbf->tbf_t = NULL;
vifp->v_flags = vifcp->vifc_flags;
vifp->v_threshold = vifcp->vifc_threshold;
vifp->v_lcl_addr = vifcp->vifc_lcl_addr;
vifp->v_rmt_addr = vifcp->vifc_rmt_addr;
vifp->v_ifp = ifp;
/* scaling up here allows division by 1024 in critical code */
vifp->v_rate_limit= vifcp->vifc_rate_limit * 1024 / 1000;
vifp->v_rsvp_on = 0;
vifp->v_rsvpd = NULL;
/* initialize per vif pkt counters */
vifp->v_pkt_in = 0;
vifp->v_pkt_out = 0;
vifp->v_bytes_in = 0;
vifp->v_bytes_out = 0;
splx(s);
/* Adjust numvifs up if the vifi is higher than numvifs */
if (numvifs <= vifcp->vifc_vifi) numvifs = vifcp->vifc_vifi + 1;
if (mrtdebug)
log(LOG_DEBUG, "add_vif #%d, lcladdr %lx, %s %lx, thresh %x, rate %d\n",
vifcp->vifc_vifi,
(u_long)ntohl(vifcp->vifc_lcl_addr.s_addr),
(vifcp->vifc_flags & VIFF_TUNNEL) ? "rmtaddr" : "mask",
(u_long)ntohl(vifcp->vifc_rmt_addr.s_addr),
vifcp->vifc_threshold,
vifcp->vifc_rate_limit);
return 0;
}
/*
* Delete a vif from the vif table
*/
static int
del_vif(vifi)
vifi_t vifi;
{
register struct vif *vifp = &viftable[vifi];
register struct mbuf *m;
struct ifnet *ifp;
struct ifreq ifr;
int s;
if (vifi >= numvifs) return EINVAL;
if (vifp->v_lcl_addr.s_addr == 0) return EADDRNOTAVAIL;
s = splnet();
if (!(vifp->v_flags & VIFF_TUNNEL)) {
((struct sockaddr_in *)&(ifr.ifr_addr))->sin_family = AF_INET;
((struct sockaddr_in *)&(ifr.ifr_addr))->sin_addr.s_addr = INADDR_ANY;
ifp = vifp->v_ifp;
if_allmulti(ifp, 0);
}
if (vifp == last_encap_vif) {
last_encap_vif = 0;
last_encap_src = 0;
}
/*
* Free packets queued at the interface
*/
while (vifp->v_tbf->tbf_q) {
m = vifp->v_tbf->tbf_q;
vifp->v_tbf->tbf_q = m->m_act;
m_freem(m);
}
bzero((caddr_t)vifp->v_tbf, sizeof(*(vifp->v_tbf)));
bzero((caddr_t)vifp, sizeof (*vifp));
if (mrtdebug)
log(LOG_DEBUG, "del_vif %d, numvifs %d\n", vifi, numvifs);
/* Adjust numvifs down */
for (vifi = numvifs; vifi > 0; vifi--)
if (viftable[vifi-1].v_lcl_addr.s_addr != 0) break;
numvifs = vifi;
splx(s);
return 0;
}
/*
* Add an mfc entry
*/
static int
add_mfc(mfccp)
struct mfcctl *mfccp;
{
struct mfc *rt;
u_long hash;
struct rtdetq *rte;
register u_short nstl;
int s;
int i;
MFCFIND(mfccp->mfcc_origin.s_addr, mfccp->mfcc_mcastgrp.s_addr, rt);
/* If an entry already exists, just update the fields */
if (rt) {
if (mrtdebug & DEBUG_MFC)
log(LOG_DEBUG,"add_mfc update o %lx g %lx p %x\n",
(u_long)ntohl(mfccp->mfcc_origin.s_addr),
(u_long)ntohl(mfccp->mfcc_mcastgrp.s_addr),
mfccp->mfcc_parent);
s = splnet();
rt->mfc_parent = mfccp->mfcc_parent;
for (i = 0; i < numvifs; i++)
rt->mfc_ttls[i] = mfccp->mfcc_ttls[i];
splx(s);
return 0;
}
/*
* Find the entry for which the upcall was made and update
*/
s = splnet();
hash = MFCHASH(mfccp->mfcc_origin.s_addr, mfccp->mfcc_mcastgrp.s_addr);
for (rt = mfctable[hash], nstl = 0; rt; rt = rt->mfc_next) {
if ((rt->mfc_origin.s_addr == mfccp->mfcc_origin.s_addr) &&
(rt->mfc_mcastgrp.s_addr == mfccp->mfcc_mcastgrp.s_addr) &&
(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 *)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 *)rt->mfc_stall);
rt->mfc_origin = mfccp->mfcc_origin;
rt->mfc_mcastgrp = mfccp->mfcc_mcastgrp;
rt->mfc_parent = mfccp->mfcc_parent;
for (i = 0; i < numvifs; i++)
rt->mfc_ttls[i] = mfccp->mfcc_ttls[i];
/* initialize pkt counters per src-grp */
rt->mfc_pkt_cnt = 0;
rt->mfc_byte_cnt = 0;
rt->mfc_wrong_if = 0;
rt->mfc_last_assert.tv_sec = rt->mfc_last_assert.tv_usec = 0;
rt->mfc_expire = 0; /* Don't clean this guy up */
nexpire[hash]--;
/* free packets Qed at the end of this entry */
for (rte = rt->mfc_stall; rte != NULL; ) {
struct rtdetq *n = rte->next;
ip_mdq(rte->m, rte->ifp, rt, -1);
m_freem(rte->m);
#ifdef UPCALL_TIMING
collate(&(rte->t));
#endif /* UPCALL_TIMING */
free(rte, M_MRTABLE);
rte = n;
}
rt->mfc_stall = NULL;
}
}
/*
* It is possible that an entry is being inserted without an upcall
*/
if (nstl == 0) {
if (mrtdebug & DEBUG_MFC)
log(LOG_DEBUG,"add_mfc no upcall h %lu o %lx g %lx p %x\n",
hash, (u_long)ntohl(mfccp->mfcc_origin.s_addr),
(u_long)ntohl(mfccp->mfcc_mcastgrp.s_addr),
mfccp->mfcc_parent);
for (rt = mfctable[hash]; rt != NULL; rt = rt->mfc_next) {
if ((rt->mfc_origin.s_addr == mfccp->mfcc_origin.s_addr) &&
(rt->mfc_mcastgrp.s_addr == mfccp->mfcc_mcastgrp.s_addr)) {
rt->mfc_origin = mfccp->mfcc_origin;
rt->mfc_mcastgrp = mfccp->mfcc_mcastgrp;
rt->mfc_parent = mfccp->mfcc_parent;
for (i = 0; i < numvifs; i++)
rt->mfc_ttls[i] = mfccp->mfcc_ttls[i];
/* initialize pkt counters per src-grp */
rt->mfc_pkt_cnt = 0;
rt->mfc_byte_cnt = 0;
rt->mfc_wrong_if = 0;
rt->mfc_last_assert.tv_sec = rt->mfc_last_assert.tv_usec = 0;
if (rt->mfc_expire)
nexpire[hash]--;
rt->mfc_expire = 0;
}
}
if (rt == NULL) {
/* no upcall, so make a new entry */
rt = (struct mfc *)malloc(sizeof(*rt), M_MRTABLE, M_NOWAIT);
if (rt == NULL) {
splx(s);
return ENOBUFS;
}
/* insert new entry at head of hash chain */
rt->mfc_origin = mfccp->mfcc_origin;
rt->mfc_mcastgrp = mfccp->mfcc_mcastgrp;
rt->mfc_parent = mfccp->mfcc_parent;
for (i = 0; i < numvifs; i++)
rt->mfc_ttls[i] = mfccp->mfcc_ttls[i];
/* initialize pkt counters per src-grp */
rt->mfc_pkt_cnt = 0;
rt->mfc_byte_cnt = 0;
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 */
rt->mfc_next = mfctable[hash];
mfctable[hash] = rt;
}
}
splx(s);
return 0;
}
#ifdef UPCALL_TIMING
/*
* collect delay statistics on the upcalls
*/
static void collate(t)
register struct timeval *t;
{
register u_long d;
register struct timeval tp;
register u_long delta;
GET_TIME(tp);
if (TV_LT(*t, tp))
{
TV_DELTA(tp, *t, delta);
d = delta >> 10;
if (d > 50)
d = 50;
++upcall_data[d];
}
}
#endif /* UPCALL_TIMING */
/*
* Delete an mfc entry
*/
static int
del_mfc(mfccp)
struct mfcctl *mfccp;
{
struct in_addr origin;
struct in_addr mcastgrp;
struct mfc *rt;
struct mfc **nptr;
u_long hash;
int s;
origin = mfccp->mfcc_origin;
mcastgrp = mfccp->mfcc_mcastgrp;
hash = MFCHASH(origin.s_addr, mcastgrp.s_addr);
if (mrtdebug & DEBUG_MFC)
log(LOG_DEBUG,"del_mfc orig %lx mcastgrp %lx\n",
(u_long)ntohl(origin.s_addr), (u_long)ntohl(mcastgrp.s_addr));
s = splnet();
nptr = &mfctable[hash];
while ((rt = *nptr) != NULL) {
if (origin.s_addr == rt->mfc_origin.s_addr &&
mcastgrp.s_addr == rt->mfc_mcastgrp.s_addr &&
rt->mfc_stall == NULL)
break;
nptr = &rt->mfc_next;
}
if (rt == NULL) {
splx(s);
return EADDRNOTAVAIL;
}
*nptr = rt->mfc_next;
free(rt, M_MRTABLE);
splx(s);
return 0;
}
/*
* Send a message to mrouted on the multicast routing socket
*/
static int
socket_send(s, mm, src)
struct socket *s;
struct mbuf *mm;
struct sockaddr_in *src;
{
if (s) {
if (sbappendaddr(&s->so_rcv,
(struct sockaddr *)src,
mm, (struct mbuf *)0) != 0) {
sorwakeup(s);
return 0;
}
}
m_freem(mm);
return -1;
}
/*
* IP multicast forwarding function. This function assumes that the packet
* pointed to by "ip" has arrived on (or is about to be sent to) the interface
* pointed to by "ifp", and the packet is to be relayed to other networks
* that have members of the packet's destination IP multicast group.
*
* The packet is returned unscathed to the caller, unless it is
* erroneous, in which case a non-zero return value tells the caller to
* discard it.
*/
#define IP_HDR_LEN 20 /* # bytes of fixed IP header (excluding options) */
#define TUNNEL_LEN 12 /* # bytes of IP option for tunnel encapsulation */
static int
X_ip_mforward(ip, ifp, m, imo)
register struct ip *ip;
struct ifnet *ifp;
struct mbuf *m;
struct ip_moptions *imo;
{
register struct mfc *rt;
register u_char *ipoptions;
static struct sockaddr_in k_igmpsrc = { sizeof k_igmpsrc, AF_INET };
static int srctun = 0;
register struct mbuf *mm;
int s;
vifi_t vifi;
struct vif *vifp;
if (mrtdebug & DEBUG_FORWARD)
log(LOG_DEBUG, "ip_mforward: src %lx, dst %lx, ifp %p\n",
(u_long)ntohl(ip->ip_src.s_addr), (u_long)ntohl(ip->ip_dst.s_addr),
(void *)ifp);
if (ip->ip_hl < (IP_HDR_LEN + TUNNEL_LEN) >> 2 ||
(ipoptions = (u_char *)(ip + 1))[1] != IPOPT_LSRR ) {
/*
* Packet arrived via a physical interface or
* an encapsulated tunnel.
*/
} else {
/*
* Packet arrived through a source-route tunnel.
* Source-route tunnels are no longer supported.
*/
if ((srctun++ % 1000) == 0)
log(LOG_ERR,
"ip_mforward: received source-routed packet from %lx\n",
(u_long)ntohl(ip->ip_src.s_addr));
return 1;
}
if ((imo) && ((vifi = imo->imo_multicast_vif) < numvifs)) {
if (ip->ip_ttl < 255)
ip->ip_ttl++; /* compensate for -1 in *_send routines */
if (rsvpdebug && ip->ip_p == IPPROTO_RSVP) {
vifp = viftable + vifi;
printf("Sending IPPROTO_RSVP from %lx to %lx on vif %d (%s%s%d)\n",
ntohl(ip->ip_src.s_addr), ntohl(ip->ip_dst.s_addr), vifi,
(vifp->v_flags & VIFF_TUNNEL) ? "tunnel on " : "",
vifp->v_ifp->if_name, vifp->v_ifp->if_unit);
}
return (ip_mdq(m, ifp, NULL, vifi));
}
if (rsvpdebug && ip->ip_p == IPPROTO_RSVP) {
printf("Warning: IPPROTO_RSVP from %lx to %lx without vif option\n",
ntohl(ip->ip_src.s_addr), ntohl(ip->ip_dst.s_addr));
if(!imo)
printf("In fact, no options were specified at all\n");
}
/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -