patch-2.1.15 linux/net/ipv4/ipmr.c
Next file: linux/net/ipv4/packet.c
Previous file: linux/net/ipv4/ipip.c
Back to the patch index
Back to the overall index
- Lines: 933
- Date:
Thu Dec 12 16:54:24 1996
- Orig file:
v2.1.14/linux/net/ipv4/ipmr.c
- Orig date:
Tue Nov 19 15:54:01 1996
diff -u --recursive --new-file v2.1.14/linux/net/ipv4/ipmr.c linux/net/ipv4/ipmr.c
@@ -12,7 +12,7 @@
*
* Fixes:
* Michael Chastain : Incorrect size of copying.
- * Alan Cox : Added the cache manager code.
+ * Alan Cox : Added the cache manager code
* Alan Cox : Fixed the clone/copy bug and device race.
* Malcolm Beattie : Buffer handling fixes.
* Alexey Kuznetsov : Double buffer free and other fixes.
@@ -59,39 +59,66 @@
static struct vif_device vif_table[MAXVIFS]; /* Devices */
static unsigned long vifc_map; /* Active device map */
+static int maxvif;
int mroute_do_pim = 0; /* Set in PIM assert */
static struct mfc_cache *mfc_cache_array[MFC_LINES]; /* Forwarding cache */
-static struct mfc_cache *cache_resolve_queue; /* Unresolved cache */
int cache_resolve_queue_len = 0; /* Size of unresolved */
/*
* Delete a VIF entry
*/
-static void vif_delete(struct vif_device *v)
+static int vif_delete(int vifi)
{
- if(!(v->flags&VIFF_TUNNEL))
- {
- v->dev->flags&=~IFF_ALLMULTI;
- dev_mc_upload(v->dev);
+ struct vif_device *v;
+
+ if (vifi < 0 || vifi >= maxvif || !(vifc_map&(1<<vifi)))
+ return -EADDRNOTAVAIL;
+
+ v = &vif_table[vifi];
+
+ start_bh_atomic();
+
+ if (!(v->flags&VIFF_TUNNEL)) {
+ v->u.dev->flags &= ~IFF_ALLMULTI;
+ dev_mc_upload(v->u.dev);
+ ip_rt_multicast_event(v->u.dev);
+ v->u.dev = NULL;
+ } else {
+ ip_rt_put(v->u.rt);
+ v->u.rt = NULL;
}
- v->dev=NULL;
+
+ vifc_map&=~(1<<vifi);
+
+ end_bh_atomic();
+
+ if (vifi+1 == maxvif) {
+ int tmp;
+ for (tmp=vifi-1; tmp>=0; tmp--) {
+ if (vifc_map&(1<<tmp))
+ break;
+ }
+ maxvif = tmp+1;
+ }
+ return 0;
}
-/*
- * Find a vif
- */
-
-static int ipmr_vifi_find(struct device *dev)
+static void ipmr_set_bounds(struct mfc_cache *cache)
{
- struct vif_device *v=&vif_table[0];
- int ct;
- for(ct=0;ct<MAXVIFS;ct++,v++)
- {
- if(v->dev==dev)
- return ct;
+ int vifi;
+ for (vifi=0; vifi<maxvif; vifi++) {
+ if (vifc_map&(1<<vifi) && cache->mfc_ttls[vifi]) {
+ cache->mfc_minvif = vifi;
+ cache->mfc_maxvif = vifi+1;
+ vifi++;
+ break;
+ }
+ }
+ for ( ; vifi<maxvif; vifi++) {
+ if (vifc_map&(1<<vifi) && cache->mfc_ttls[vifi])
+ cache->mfc_maxvif = vifi+1;
}
- return -1;
}
/*
@@ -108,16 +135,11 @@
* Find the right cache line
*/
+ line=MFC_HASH(cache->mfc_mcastgrp,cache->mfc_origin);
+ cp=&(mfc_cache_array[line]);
+
if(cache->mfc_flags&MFC_QUEUED)
- {
- cp=&cache_resolve_queue;
del_timer(&cache->mfc_timer);
- }
- else
- {
- line=MFC_HASH(cache->mfc_mcastgrp,cache->mfc_origin);
- cp=&(mfc_cache_array[line]);
- }
/*
* Unlink the buffer
@@ -176,6 +198,7 @@
{
int line=MFC_HASH(mcastgrp,origin);
struct mfc_cache *cache;
+
cache=mfc_cache_array[line];
while(cache!=NULL)
{
@@ -183,13 +206,6 @@
return cache;
cache=cache->next;
}
- cache=cache_resolve_queue;
- while(cache!=NULL)
- {
- if(cache->mfc_origin==origin && cache->mfc_mcastgrp==mcastgrp)
- return cache;
- cache=cache->next;
- }
return NULL;
}
@@ -207,6 +223,9 @@
init_timer(&c->mfc_timer);
c->mfc_timer.data=(long)c;
c->mfc_timer.function=ipmr_cache_timer;
+ c->mfc_last_assert=0;
+ c->mfc_minvif = MAXVIFS;
+ c->mfc_maxvif = 0;
return c;
}
@@ -216,37 +235,28 @@
static void ipmr_cache_resolve(struct mfc_cache *cache)
{
- struct mfc_cache **p;
struct sk_buff *skb;
+
+ start_bh_atomic();
+
/*
* Kill the queue entry timer.
*/
+
del_timer(&cache->mfc_timer);
- cache->mfc_flags&=~MFC_QUEUED;
- /*
- * Remove from the resolve queue
- */
- p=&cache_resolve_queue;
- while((*p)!=NULL)
- {
- if((*p)==cache)
- {
- *p=cache->next;
- break;
- }
- p=&((*p)->next);
+
+ if (cache->mfc_flags&MFC_QUEUED) {
+ cache->mfc_flags&=~MFC_QUEUED;
+ cache_resolve_queue_len--;
}
- cache_resolve_queue_len--;
- sti();
- /*
- * Insert into the main cache
- */
- ipmr_cache_insert(cache);
+
+ end_bh_atomic();
+
/*
* Play the pending entries through our router
*/
while((skb=skb_dequeue(&cache->mfc_unresolved)))
- ipmr_forward(skb, skb->protocol);
+ ip_mr_input(skb);
}
/*
@@ -254,50 +264,52 @@
* expects the following bizarre scheme..
*/
-static void ipmr_cache_report(struct sk_buff *pkt)
+static void ipmr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert)
{
- struct sk_buff *skb=alloc_skb(128, GFP_ATOMIC);
- int ihl=pkt->ip_hdr->ihl<<2;
+ struct sk_buff *skb = alloc_skb(128, GFP_ATOMIC);
+ int ihl = pkt->nh.iph->ihl<<2;
struct igmphdr *igmp;
+ struct igmpmsg *msg;
+
if(!skb)
return;
- skb->free=1;
-
/*
* Copy the IP header
*/
- skb->ip_hdr=(struct iphdr *)skb_put(skb,ihl);
- skb->h.iph=skb->ip_hdr;
+ skb->nh.iph = (struct iphdr *)skb_put(skb, ihl);
memcpy(skb->data,pkt->data,ihl);
- skb->ip_hdr->protocol = 0; /* Flag to the kernel this is a route add */
+ skb->nh.iph->protocol = 0; /* Flag to the kernel this is a route add */
+ msg = (struct igmpmsg*)skb->nh.iph;
+ if (assert)
+ msg->im_vif = vifi;
/*
* Add our header
*/
igmp=(struct igmphdr *)skb_put(skb,sizeof(struct igmphdr));
- igmp->type = IGMPMSG_NOCACHE; /* non IGMP dummy message */
+ igmp->type =
+ msg->im_msgtype = assert ? IGMPMSG_WRONGVIF : IGMPMSG_NOCACHE;
igmp->code = 0;
- skb->ip_hdr->tot_len=htons(skb->len); /* Fix the length */
+ skb->nh.iph->tot_len=htons(skb->len); /* Fix the length */
+ skb->h.raw = skb->nh.raw;
/*
* Deliver to mrouted
*/
if(sock_queue_rcv_skb(mroute_socket,skb)<0)
{
- skb->sk=NULL;
kfree_skb(skb, FREE_READ);
}
}
-
-
+
/*
* Queue a packet for resolution
*/
-static void ipmr_cache_unresolved(struct mfc_cache *cache, vifi_t vifi, struct sk_buff *skb, int is_frag)
+static void ipmr_cache_unresolved(struct mfc_cache *cache, vifi_t vifi, struct sk_buff *skb)
{
if(cache==NULL)
{
@@ -313,14 +325,13 @@
* Fill in the new cache entry
*/
cache->mfc_parent=vifi;
- cache->mfc_origin=skb->ip_hdr->saddr;
- cache->mfc_mcastgrp=skb->ip_hdr->daddr;
+ cache->mfc_origin=skb->nh.iph->saddr;
+ cache->mfc_mcastgrp=skb->nh.iph->daddr;
cache->mfc_flags=MFC_QUEUED;
/*
* Link to the unresolved list
*/
- cache->next=cache_resolve_queue;
- cache_resolve_queue=cache;
+ ipmr_cache_insert(cache);
cache_resolve_queue_len++;
/*
* Fire off the expiry timer
@@ -331,7 +342,7 @@
* Reflect first query at mrouted.
*/
if(mroute_socket)
- ipmr_cache_report(skb);
+ ipmr_cache_report(skb, vifi, 0);
}
/*
* See if we can append the packet
@@ -341,12 +352,7 @@
kfree_skb(skb, FREE_WRITE);
return;
}
- /*
- * Add to our 'pending' list. Cache the is_frag data
- * in skb->protocol now it is spare.
- */
cache->mfc_queuelen++;
- skb->protocol=is_frag;
skb_queue_tail(&cache->mfc_unresolved,skb);
}
@@ -357,13 +363,14 @@
int ipmr_mfc_modify(int action, struct mfcctl *mfc)
{
struct mfc_cache *cache;
+
if(!MULTICAST(mfc->mfcc_mcastgrp.s_addr))
return -EINVAL;
/*
* Find the cache line
*/
- cli();
+ start_bh_atomic();
cache=ipmr_cache_find(mfc->mfcc_origin.s_addr,mfc->mfcc_mcastgrp.s_addr);
@@ -375,20 +382,23 @@
if(cache)
{
ipmr_cache_delete(cache);
- sti();
+ end_bh_atomic();
return 0;
}
- sti();
+ end_bh_atomic();
return -ENOENT;
}
if(cache)
{
+
/*
* Update the cache, see if it frees a pending queue
*/
cache->mfc_flags|=MFC_RESOLVED;
+ cache->mfc_parent=mfc->mfcc_parent;
memcpy(cache->mfc_ttls, mfc->mfcc_ttls,sizeof(cache->mfc_ttls));
+ ipmr_set_bounds(cache);
/*
* Check to see if we resolved a queued list. If so we
@@ -397,9 +407,10 @@
if(cache->mfc_flags&MFC_QUEUED)
ipmr_cache_resolve(cache); /* Unhook & send the frames */
- sti();
+ end_bh_atomic();
return 0;
}
+
/*
* Unsolicited update - that's ok, add anyway.
*/
@@ -408,7 +419,7 @@
cache=ipmr_cache_alloc(GFP_ATOMIC);
if(cache==NULL)
{
- sti();
+ end_bh_atomic();
return -ENOMEM;
}
cache->mfc_flags=MFC_RESOLVED;
@@ -416,8 +427,9 @@
cache->mfc_mcastgrp=mfc->mfcc_mcastgrp.s_addr;
cache->mfc_parent=mfc->mfcc_parent;
memcpy(cache->mfc_ttls, mfc->mfcc_ttls,sizeof(cache->mfc_ttls));
+ ipmr_set_bounds(cache);
ipmr_cache_insert(cache);
- sti();
+ end_bh_atomic();
return 0;
}
@@ -458,9 +470,11 @@
if(mroute_socket)
return -EADDRINUSE;
mroute_socket=sk;
+ ipv4_config.multicast_route = 1;
/* Initialise state */
return 0;
case MRT_DONE:
+ ipv4_config.multicast_route = 0;
mroute_close(sk);
mroute_socket=NULL;
return 0;
@@ -481,7 +495,7 @@
if(vifc_map&(1<<vif.vifc_vifi))
return -EADDRINUSE;
/* Find the interface */
- dev=ip_dev_find(vif.vifc_lcl_addr.s_addr);
+ dev=ip_dev_find(vif.vifc_lcl_addr.s_addr, NULL);
if(!dev)
return -EADDRNOTAVAIL;
/* Must be tunnelled or multicastable */
@@ -489,7 +503,6 @@
{
if(vif.vifc_flags&VIFF_SRCRT)
return -EOPNOTSUPP;
- /* IPIP will do all the work */
}
else
{
@@ -499,6 +512,7 @@
how to do this yet.. */
dev->flags|=IFF_ALLMULTI;
dev_mc_upload(dev);
+ ip_rt_multicast_event(dev);
}
else
{
@@ -515,30 +529,21 @@
v->remote=vif.vifc_rmt_addr.s_addr;
v->flags=vif.vifc_flags;
v->threshold=vif.vifc_threshold;
- v->dev=dev;
+ v->u.dev=NULL;
+ if (!(vif.vifc_flags&VIFF_TUNNEL))
+ v->u.dev=dev;
v->bytes_in = 0;
v->bytes_out = 0;
v->pkt_in = 0;
v->pkt_out = 0;
vifc_map|=(1<<vif.vifc_vifi);
+ if (vif.vifc_vifi+1 > maxvif)
+ maxvif = vif.vifc_vifi+1;
sti();
return 0;
- }
- else
- /*
- * VIF deletion
- */
- {
- struct vif_device *v=&vif_table[vif.vifc_vifi];
- if(vifc_map&(1<<vif.vifc_vifi))
- {
- vif_delete(v);
- vifc_map&=~(1<<vif.vifc_vifi);
- return 0;
- }
- else
- return -EADDRNOTAVAIL;
- }
+ } else
+ return vif_delete(vif.vifc_vifi);
+
/*
* Manipulate the forwarding caches. These live
* in a sort of kernel/user symbiosis.
@@ -609,6 +614,7 @@
struct sioc_sg_req sr;
struct sioc_vif_req vr;
struct vif_device *vif;
+ struct mfc_cache *c;
switch(cmd)
{
@@ -616,7 +622,7 @@
err = copy_from_user(&vr,(void *)arg,sizeof(vr));
if (err)
return -EFAULT;
- if(vr.vifi>=MAXVIFS)
+ if(vr.vifi>=maxvif)
return -EINVAL;
vif=&vif_table[vr.vifi];
if(vifc_map&(1<<vr.vifi))
@@ -629,15 +635,28 @@
if (err)
err = -EFAULT;
return err;
+ return 0;
}
return -EADDRNOTAVAIL;
case SIOCGETSGCNT:
err = copy_from_user(&sr,(void *)arg,sizeof(sr));
- if (!err)
- err = copy_to_user((void *)arg,&sr,sizeof(sr));
if (err)
- err = -EFAULT;
- return err;
+ return -EFAULT;
+ for (c = mfc_cache_array[MFC_HASH(sr.grp.s_addr, sr.src.s_addr)];
+ c; c = c->next) {
+ if (sr.grp.s_addr == c->mfc_mcastgrp &&
+ sr.src.s_addr == c->mfc_origin) {
+ sr.pktcnt = c->mfc_pkt;
+ sr.bytecnt = c->mfc_bytes;
+ sr.wrong_if = c->mfc_wrong_if;
+ err = copy_to_user((void *)arg,&sr,sizeof(sr));
+ if (err)
+ err = -EFAULT;
+ return err;
+ return 0;
+ }
+ }
+ return -EADDRNOTAVAIL;
default:
return -EINVAL;
}
@@ -650,34 +669,24 @@
void mroute_close(struct sock *sk)
{
int i;
- struct vif_device *v=&vif_table[0];
/*
* Shut down all active vif entries
*/
- for(i=0;i<MAXVIFS;i++)
- {
- if(vifc_map&(1<<i))
- {
- if(!(v->flags&VIFF_TUNNEL))
- {
- v->dev->flags&=~IFF_ALLMULTI;
- dev_mc_upload(v->dev);
- }
- }
- v++;
- }
- vifc_map=0;
+ for(i=0; i<maxvif; i++)
+ vif_delete(i);
+
/*
* Wipe the cache
*/
for(i=0;i<MFC_LINES;i++)
{
+ start_bh_atomic();
while(mfc_cache_array[i]!=NULL)
ipmr_cache_delete(mfc_cache_array[i]);
- }
- /* The timer will clear any 'pending' stuff */
+ end_bh_atomic();
+ }
}
static int ipmr_device_event(struct notifier_block *this, unsigned long event, void *ptr)
@@ -687,13 +696,10 @@
if(event!=NETDEV_DOWN)
return NOTIFY_DONE;
v=&vif_table[0];
- for(ct=0;ct<MAXVIFS;ct++)
+ for(ct=0;ct<maxvif;ct++)
{
- if((vifc_map&(1<<ct)) && v->dev==ptr)
- {
- vif_delete(v);
- vifc_map&=~(1<<ct);
- }
+ if(vifc_map&(1<<ct) && !(v->flags&VIFF_TUNNEL) && v->u.dev==ptr)
+ vif_delete(ct);
v++;
}
return NOTIFY_DONE;
@@ -707,104 +713,204 @@
};
/*
+ * Encapsulate a packet by attaching a valid IPIP header to it.
+ * This avoids tunnel drivers and other mess and gives us the speed so
+ * important for multicast video.
+ */
+
+static void ip_encap(struct sk_buff *skb, u32 saddr, u32 daddr)
+{
+ struct iphdr *iph = (struct iphdr *)skb_push(skb,sizeof(struct iphdr));
+
+ iph->version = 4;
+ iph->tos = skb->nh.iph->tos;
+ iph->ttl = skb->nh.iph->ttl;
+ iph->frag_off = 0;
+ iph->daddr = daddr;
+ iph->saddr = saddr;
+ iph->protocol = IPPROTO_IPIP;
+ iph->ihl = 5;
+ iph->tot_len = htons(skb->len);
+ iph->id = htons(ip_id_count++);
+ ip_send_check(iph);
+
+ skb->h.ipiph = skb->nh.iph;
+ skb->nh.iph = iph;
+}
+
+/*
* Processing handlers for ipmr_forward
*/
-static void ipmr_queue_xmit(struct sk_buff *skb, struct vif_device *vif, struct device *in_dev, int frag)
+static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c,
+ int vifi, int last)
{
- int tunnel=0;
- __u32 raddr=skb->raddr;
- if(vif->flags&VIFF_TUNNEL)
- {
- tunnel=IPFWD_MULTITUNNEL;
- raddr=vif->remote;
+ struct iphdr *iph = skb->nh.iph;
+ struct vif_device *vif = &vif_table[vifi];
+ struct device *dev;
+ struct rtable *rt;
+ int encap = 0;
+ struct sk_buff *skb2;
+ int err;
+
+ if (vif->flags&VIFF_TUNNEL) {
+ rt = vif->u.rt;
+ if (!rt || rt->u.dst.obsolete) {
+ ip_rt_put(rt);
+ vif->u.rt = NULL;
+ err = ip_route_output(&rt, vif->remote, vif->local, RT_TOS(iph->tos), NULL);
+ if (err)
+ return;
+ vif->u.rt = rt;
+ }
+ dst_clone(&rt->u.dst);
+ encap = sizeof(struct iphdr);
+ } else {
+ dev = vif->u.dev;
+ if (dev == NULL)
+ return;
+ err = ip_route_output(&rt, iph->daddr, 0, RT_TOS(iph->tos), dev);
+ if (err)
+ return;
+ }
+
+ dev = rt->u.dst.dev;
+
+ if (skb->len+encap > dev->mtu && (ntohs(iph->frag_off) & IP_DF)) {
+ ip_statistics.IpFragFails++;
+ ip_rt_put(rt);
+ return;
}
+
+ encap += dev->hard_header_len;
+
+ if (skb->len+encap > 65534) {
+ ip_rt_put(rt);
+ return;
+ }
+
+ if (skb_headroom(skb) < encap || (encap && !last))
+ skb2 = skb_realloc_headroom(skb, (encap + 15)&~15);
+ else
+ skb2 = skb_clone(skb, GFP_ATOMIC);
+
+ if (skb2 == NULL) {
+ ip_rt_put(rt);
+ return;
+ }
+
vif->pkt_out++;
vif->bytes_out+=skb->len;
- skb->dev=vif->dev;
- skb->raddr=skb->h.iph->daddr;
- /*
- * If the vif went down as we were forwarding.. just throw the
- * frame.
- */
- if(vif->dev==NULL || ip_forward(skb, in_dev, frag|IPFWD_MULTICASTING|tunnel, raddr)==-1)
- kfree_skb(skb, FREE_WRITE);
+
+ dst_release(skb2->dst);
+ skb2->dst = &rt->u.dst;
+
+ iph = skb2->nh.iph;
+ ip_decrease_ttl(iph);
+
+ if (vif->flags & VIFF_TUNNEL)
+ ip_encap(skb2, vif->local, vif->remote);
+
+ ip_send(skb2);
}
/*
* Multicast packets for forwarding arrive here
*/
-void ipmr_forward(struct sk_buff *skb, int is_frag)
+int ip_mr_input(struct sk_buff *skb)
{
struct mfc_cache *cache;
- struct sk_buff *skb2;
int psend = -1;
- int vif=ipmr_vifi_find(skb->dev);
- if(vif==-1)
- {
- kfree_skb(skb, FREE_WRITE);
- return;
+ int vif, ct;
+ int local = 0;
+ int tunneled = IPCB(skb)->flags&IPSKB_TUNNELED;
+
+ cache = ipmr_cache_find(skb->nh.iph->saddr, skb->nh.iph->daddr);
+
+ /*
+ * No usable cache entry
+ */
+
+ if (cache==NULL || (cache->mfc_flags&MFC_QUEUED)) {
+ ipmr_cache_unresolved(cache, ALL_VIFS, skb);
+ return -EAGAIN;
}
+ vif = cache->mfc_parent;
+ cache->mfc_pkt++;
+ cache->mfc_bytes += skb->len;
+
/*
- * Without the following addition, skb->h.iph points to something
- * different that is not the ip header.
+ * Wrong interface: drop packet and (maybe) send PIM assert.
*/
-
- skb->h.iph = skb->ip_hdr; /* Anand, ernet. */
+ if (vif >= maxvif || !(vifc_map&(1<<vif)) ||
+ (tunneled && IPCB(skb)->vif != vif) ||
+ (!tunneled && (vif_table[vif].flags&VIFF_TUNNEL ||
+ vif_table[vif].u.dev != skb->dev))) {
+ cache->mfc_wrong_if++;
+ if (vif < MAXVIFS && mroute_do_pim &&
+ !(vif_table[vif].flags&VIFF_TUNNEL) &&
+ skb->dev->flags&IFF_BROADCAST &&
+ jiffies - cache->mfc_last_assert > MFC_ASSERT_THRESH) {
+ cache->mfc_last_assert = jiffies;
+ /*
+ * It is wrong! Routing daemon can
+ * determine vif itself, but it cannot
+ * determine REAL device.
+ * BSD bug. Fix it later, PIM does not
+ * work in any case 8) _ANK_
+ */
+ ipmr_cache_report(skb, vif, 1);
+ }
+ kfree_skb(skb, FREE_WRITE);
+ return -EINVAL;
+ }
vif_table[vif].pkt_in++;
vif_table[vif].bytes_in+=skb->len;
-
- cache=ipmr_cache_find(skb->ip_hdr->saddr,skb->ip_hdr->daddr);
-
+
+ if (IPCB(skb)->opt.router_alert ||
+ ((struct rtable*)skb->dst)->rt_flags&RTF_LOCAL ||
+ skb->nh.iph->protocol == IPPROTO_IGMP)
+ local = 1;
+
/*
- * No usable cache entry
+ * Forward the frame
*/
-
- if(cache==NULL || (cache->mfc_flags&MFC_QUEUED))
- ipmr_cache_unresolved(cache,vif,skb, is_frag);
- else
- {
+ ct = cache->mfc_maxvif-1;
+ while (ct>=cache->mfc_minvif) {
/*
- * Forward the frame
+ * 0 means don't do it. Silly idea, 255 as don't do it would be cleaner!
*/
- int ct=0;
- while(ct<MAXVIFS)
- {
- /*
- * 0 means don't do it. Silly idea, 255 as don't do it would be cleaner!
- */
- if(skb->ip_hdr->ttl > cache->mfc_ttls[ct] && cache->mfc_ttls[ct]>0)
- {
- if(psend!=-1)
- {
- /*
- * May get variant mac headers
- * so must copy -- boo hoo.
- */
- skb2=skb_copy(skb, GFP_ATOMIC);
- if(skb2)
- {
- skb2->free=1;
- ipmr_queue_xmit(skb2, &vif_table[psend], skb->dev, is_frag);
- }
- }
- psend=ct;
- }
- ct++;
+ if (skb->nh.iph->ttl > cache->mfc_ttls[ct] && cache->mfc_ttls[ct]>0) {
+ if (psend != -1)
+ ipmr_queue_xmit(skb, cache, psend, 0);
+ psend=ct;
}
- if(psend==-1)
- kfree_skb(skb, FREE_WRITE);
- else
- {
- ipmr_queue_xmit(skb, &vif_table[psend], skb->dev, is_frag);
- }
- /*
- * Adjust the stats
- */
+ ct--;
}
+ if (psend != -1)
+ ipmr_queue_xmit(skb, cache, psend, 1);
+ if (!local) {
+ kfree_skb(skb, FREE_READ);
+ return 0;
+ }
+ return ip_local_deliver(skb);
+}
+
+int ip_mr_find_tunnel(u32 local, u32 remote)
+{
+ int ct;
+ struct vif_device *vif;
+
+ for (ct=0; ct<maxvif; ct++) {
+ vif = &vif_table[ct];
+ if (vifc_map&(1<<ct) && vif->flags&VIFF_TUNNEL &&
+ vif->local == local && vif->remote == remote)
+ return ct;
+ }
+ return -1;
}
/*
@@ -824,15 +930,13 @@
"Interface Bytes In Pkts In Bytes Out Pkts Out Flags Local Remote\n");
pos=len;
- for (ct=0;ct<MAXVIFS;ct++)
+ for (ct=0;ct<maxvif;ct++)
{
vif=&vif_table[ct];
if(!(vifc_map&(1<<ct)))
continue;
- if(vif->dev==NULL)
- continue;
- size = sprintf(buffer+len, "%-10s %8ld %7ld %8ld %7ld %05X %08lX %08lX\n",
- vif->dev->name,vif->bytes_in, vif->pkt_in, vif->bytes_out,vif->pkt_out,
+ size = sprintf(buffer+len, "%2d %-10s %8ld %7ld %8ld %7ld %05X %08lX %08lX\n",
+ ct, vif->flags&VIFF_TUNNEL ? "Tunnel" : vif->u.dev->name, vif->bytes_in, vif->pkt_in, vif->bytes_out, vif->pkt_out,
vif->flags, vif->local, vif->remote);
len+=size;
pos+=size;
@@ -862,40 +966,44 @@
int ct;
len += sprintf(buffer,
- "Group Origin SrcIface \n");
+ "Group Origin SrcIface Pkts Bytes Wrong VifTtls\n");
pos=len;
for (ct=0;ct<MFC_LINES;ct++)
{
- cli();
+ start_bh_atomic();
mfc=mfc_cache_array[ct];
while(mfc!=NULL)
{
char *name="none";
- char vifmap[MAXVIFS+1];
int n;
/*
* Device name
*/
- if(vifc_map&(1<<mfc->mfc_parent))
- name=vif_table[mfc->mfc_parent].dev->name;
- /*
- * Interface forwarding map
- */
- for(n=0;n<MAXVIFS;n++)
- if(vifc_map&(1<<n) && mfc->mfc_ttls[ct])
- vifmap[n]='X';
+ if(mfc->mfc_parent < maxvif && vifc_map&(1<<mfc->mfc_parent)) {
+ if (vif_table[mfc->mfc_parent].flags&VIFF_TUNNEL)
+ name="Tunnel";
else
- vifmap[n]='-';
- vifmap[n]=0;
+ name=vif_table[mfc->mfc_parent].u.dev->name;
+ }
/*
- * Now print it out
+ * Interface forwarding map
*/
- size = sprintf(buffer+len, "%08lX %08lX %-8s %s\n",
+ size = sprintf(buffer+len, "%08lX %08lX %-8s %8ld %8ld %8ld",
(unsigned long)mfc->mfc_mcastgrp,
(unsigned long)mfc->mfc_origin,
name,
- vifmap);
+ mfc->mfc_bytes,
+ mfc->mfc_pkt,
+ mfc->mfc_wrong_if);
+ for(n=0;n<maxvif;n++)
+ {
+ if(vifc_map&(1<<n))
+ size += sprintf(buffer+len+size, " %-3d", mfc->mfc_ttls[n]);
+ else
+ size += sprintf(buffer+len+size, " --- ");
+ }
+ size += sprintf(buffer+len+size, "\n");
len+=size;
pos+=size;
if(pos<offset)
@@ -910,7 +1018,7 @@
}
mfc=mfc->next;
}
- sti();
+ end_bh_atomic();
}
done:
*start=buffer+(offset-begin);
@@ -934,6 +1042,7 @@
ipmr_mfc_info
};
#endif
+
/*
* Setup for IP multicast routing
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov