?? iproute.c
字號:
qhdr.gateway = gateway;
if(iface->outq == NULL){
/* Queue empty, no priority decisions to be made
* This is the usual case for fast networks like Ethernet,
* so we can avoid some time-consuming stuff
*/
pushdown(bpp,&qhdr,sizeof(qhdr));
iface->outq = *bpp;
*bpp = NULL;
} else {
/* See if this packet references a "priority" TCP port number */
if(ip->protocol == TCP_PTCL && ip->offset == 0){
/* Extract a copy of the TCP header */
if(dup_p(&tbp,*bpp,sizeof(struct qhdr)+IPLEN+
ip->optlen,TCPLEN+TCP_MAXOPT) >= TCPLEN){
ntohtcp(&tcp,&tbp);
for(i=0;Tcp_interact[i] != -1;i++){
if(tcp.source == Tcp_interact[i]
|| tcp.dest == Tcp_interact[i]){
qhdr.tos |= 1;
break;
}
}
}
free_p(&tbp);
}
pushdown(bpp,&qhdr,sizeof(qhdr));
/* Search the queue looking for the first packet with precedence
* lower than our packet
*/
tlast = NULL;
for(tbp = iface->outq;tbp != NULL;tlast=tbp,tbp = tbp->anext){
memcpy(&qtmp,tbp->data,sizeof(qtmp));
if(qhdr.tos > qtmp.tos){
break; /* Add it just before tbp */
}
}
(*bpp)->anext = tbp;
if(tlast == NULL){
/* First on queue */
iface->outq = *bpp;
} else {
tlast->anext = *bpp;
}
*bpp = NULL;
}
ksignal(&iface->outq,1);
if(iface->outlim != 0 && len_q(iface->outq) >= iface->outlim){
/* Output queue is at limit; return source quench to
* the sender of a randomly selected packet on the queue
*/
rquench(iface,0);
}
return 0;
}
int
ip_encap(
struct mbuf **bpp,
struct iface *iface,
int32 gateway,
uint8 tos
){
struct ip ip;
dump(iface,IF_TRACE_OUT,*bpp);
iface->rawsndcnt++;
iface->lastsent = secclock();
if(gateway == 0L){
/* Gateway must be specified */
ntohip(&ip,bpp);
icmp_output(&ip,*bpp,ICMP_DEST_UNREACH,ICMP_HOST_UNREACH,NULL);
free_p(bpp);
ipOutNoRoutes++;
return -1;
}
/* Encapsulate in an IP packet from us to the gateway.
* The outer source address is taken from the encap interface
* structure. This defaults to INADDR_ANY, so unless it is
* changed (with iface encap ipaddr ...), the IP address
* of the physical interface used to reach the encap gateway
* will be used.
*/
return ip_send(Encap.addr,gateway,IP_PTCL,tos,0,bpp,0,0,0);
}
/* Add an entry to the IP routing table. Returns 0 on success, -1 on failure */
struct route *
rt_add(
int32 target, /* Target IP address prefix */
unsigned int bits, /* Size of target address prefix in bits (0-32) */
int32 gateway, /* Optional gateway to be reached via interface */
struct iface *iface, /* Interface to which packet is to be routed */
int32 metric, /* Metric for this route entry */
int32 ttl, /* Lifetime of this route entry in sec */
uint8 private /* Inhibit advertising this entry ? */
){
struct route *rp,**hp;
int i;
if(iface == NULL)
return NULL;
if(bits > 32)
bits = 32; /* Bulletproofing */
if(bits == 32 && ismyaddr(target))
return NULL; /* Don't accept routes to ourselves */
/* Mask off don't-care bits of target */
target &= ~0L << (32-bits);
/* Encapsulated routes must specify gateway, and it can't be
* ourselves
*/
if(iface == &Encap && (gateway == 0 || ismyaddr(gateway)))
return NULL;
for(i=0;i<HASHMOD;i++)
Rt_cache[i].route = NULL; /* Flush cache */
/* Zero bits refers to the default route */
if(bits == 0){
rp = &R_default;
} else {
rp = rt_blookup(target,bits);
}
if(rp == NULL){
/* The target is not already in the table, so create a new
* entry and put it in.
*/
rp = (struct route *)callocw(1,sizeof(struct route));
/* Insert at head of table */
rp->prev = NULL;
hp = &Routes[bits-1][hash_ip(target)];
rp->next = *hp;
if(rp->next != NULL)
rp->next->prev = rp;
*hp = rp;
rp->uses = 0;
}
rp->target = target;
rp->bits = bits;
rp->gateway = gateway;
rp->metric = metric;
rp->iface = iface;
rp->flags.rtprivate = private; /* Should anyone be told of this route? */
rp->timer.func = rt_timeout; /* Set the timer field */
rp->timer.arg = (void *)rp;
set_timer(&rp->timer,ttl*1000L);
stop_timer(&rp->timer);
start_timer(&rp->timer); /* start the timer if appropriate */
return rp;
}
/* Remove an entry from the IP routing table. Returns 0 on success, -1
* if entry was not in table.
*/
int
rt_drop(
int32 target,
unsigned int bits
){
register struct route *rp;
int i;
for(i=0;i<HASHMOD;i++)
Rt_cache[i].route = NULL; /* Flush the cache */
if(bits == 0){
/* Nail the default entry */
stop_timer(&R_default.timer);
R_default.iface = NULL;
return 0;
}
if(bits > 32)
bits = 32;
/* Mask off target according to width */
target &= ~0L << (32-bits);
/* Search appropriate chain for existing entry */
for(rp = Routes[bits-1][hash_ip(target)];rp != NULL;rp = rp->next){
if(rp->target == target)
break;
}
if(rp == NULL)
return -1; /* Not in table */
stop_timer(&rp->timer);
if(rp->next != NULL)
rp->next->prev = rp->prev;
if(rp->prev != NULL)
rp->prev->next = rp->next;
else
Routes[bits-1][hash_ip(target)] = rp->next;
free(rp);
return 0;
}
#ifdef notdef
/* Compute hash function on IP address */
static uint16
hash_ip(
int32 addr
){
register uint16 ret;
ret = hiword(addr);
ret ^= loword(addr);
return (uint16)(ret % HASHMOD);
}
#endif
#ifndef GWONLY
/* Given an IP address, return the MTU of the local interface used to
* reach that destination. This is used by TCP to avoid local fragmentation
*/
uint16
ip_mtu(
int32 addr
){
register struct route *rp;
struct iface *iface;
rp = rt_lookup(addr);
if(rp == NULL || rp->iface == NULL)
return 0;
if(rp->iface == &Encap){
/* Recurse to the actual hardware interface */
return ip_mtu(rp->gateway) - IPLEN; /* no options? */
}
iface = rp->iface;
#ifdef IPSEC
if(iface->forw != NULL)
return iface->forw->mtu - sec_overhead(addr);
else
return iface->mtu - sec_overhead(addr);
#else
if(iface->forw != NULL)
return iface->forw->mtu;
else
return iface->mtu;
#endif
}
/* Given a destination address, return the IP address of the local
* interface that will be used to reach it. If there is no route
* to the destination, pick the first non-loopback address.
*/
int32
locaddr(addr)
int32 addr;
{
register struct route *rp;
struct iface *ifp;
if(ismyaddr(addr) != NULL)
return addr; /* Loopback case */
if((rp = rt_lookup(addr)) != NULL)
ifp = rp->iface;
else
ifp = NULL;
if(ifp == &Encap){
if((rp = rt_lookup(rp->gateway)) != NULL)
ifp = rp->iface;
else
ifp = NULL;
}
if(ifp == NULL){
/* No route currently exists, so just pick the first real
* interface and use its address
*/
for(ifp = Ifaces;ifp != NULL;ifp = ifp->next){
if(ifp != &Loopback && ifp != &Encap)
break;
}
}
if(ifp == NULL || ifp == &Loopback)
return 0; /* No dice */
if(ifp->forw != NULL)
return ifp->forw->addr;
else
return ifp->addr;
}
#endif
/* Look up target in hash table, matching the entry having the largest number
* of leading bits in common. Return default route if not found;
* if default route not set, return NULL
*/
struct route *
rt_lookup(target)
int32 target;
{
register struct route *rp;
int bits;
int32 tsave;
int32 mask;
struct rt_cache *rcp;
Rtlookups++;
/* Examine cache first */
rcp = &Rt_cache[hash_ip(target)];
if(target == rcp->target && (rp = rcp->route) != NULL){
Rtchits++;
return rp;
}
tsave = target;
mask = ~0; /* All ones */
for(bits = 31;bits >= 0; bits--){
target &= mask;
for(rp = Routes[bits][hash_ip(target)];rp != NULL;rp = rp->next){
if(rp->target != target
|| (rp->iface == &Encap && rp->gateway == tsave))
continue;
/* Stash in cache and return */
rcp->target = tsave;
rcp->route = rp;
return rp;
}
mask <<= 1;
}
if(R_default.iface != NULL){
rcp->target = tsave;
rcp->route = &R_default;
return &R_default;
} else
return NULL;
}
/* Search routing table for entry with specific width */
struct route *
rt_blookup(target,bits)
int32 target;
unsigned int bits;
{
register struct route *rp;
if(bits == 0){
if(R_default.iface != NULL)
return &R_default;
else
return NULL;
}
/* Mask off target according to width */
target &= ~0L << (32-bits);
for(rp = Routes[bits-1][hash_ip(target)];rp != NULL;rp = rp->next){
if(rp->target == target){
return rp;
}
}
return NULL;
}
/* Scan the routing table. For each entry, see if there's a less-specific
* one that points to the same interface and gateway. If so, delete
* the more specific entry, since it is redundant.
*/
void
rt_merge(
int trace
){
int bits,i,j;
struct route *rp,*rpnext,*rp1;
for(bits=32;bits>0;bits--){
for(i = 0;i<HASHMOD;i++){
for(rp = Routes[bits-1][i];rp != NULL;rp = rpnext){
rpnext = rp->next;
for(j=bits-1;j >= 0;j--){
if((rp1 = rt_blookup(rp->target,j)) != NULL
&& rp1->iface == rp->iface
&& rp1->gateway == rp->gateway){
if(trace > 1)
printf("merge %s %d\n",
inet_ntoa(rp->target),
rp->bits);
rt_drop(rp->target,rp->bits);
break;
}
}
}
}
}
}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -