Subject: Multicast routing and unnumbered point-to-point interfaces
To: None <tech-net@netbsd.org>
From: Jason R Thorpe <thorpej@zembu.com>
List: tech-net
Date: 10/05/2000 15:24:34
--BOKacYhQ+x31HxR3
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Folks...

I have routers with a large number of unnumbered point-to-point
interfaces (`gif' tunnels), and I need to do multicast routing
on them.

This required some hacking in mrouted and the kernel in order to
decouple the notion of "IP address" from "interface identifier".

I did this in two stages:

	- Rip out support for mrouted-created v4-in-v4 tunnels.
	  They are wire-compatible with gif(4), which is more
	  generic, so we should just use the generic mechanism.

	- Changed the MRT_ADD_VIF socket option to pass an
	  interface name rather than an IP address.  I left
	  the old version in there as OMRT_ADD_VIF so that
	  old mrouted(8) versions would continue to work, so
	  long as they did not use VIFF_TUNNEL (which could
	  not work, since I ripped out all the kernel support
	  for it :-).

I still have some changes to mrouted(8) to make, and some debugging
and more hacking to do, but I wanted to present this idea here in the
hopes of folding it back into NetBSD, rather than maintaining this
local change forever.

Kernel diff attached.  Please comment.

-- 
        -- Jason R. Thorpe <thorpej@zembu.com>

--BOKacYhQ+x31HxR3
Content-Type: text/plain; charset=us-ascii
Content-Description: ip_mroute.diff
Content-Disposition: attachment; filename=foo

Index: ip_mroute.c
===================================================================
RCS file: /home/cvsfiles/netbsd/src/sys/netinet/ip_mroute.c,v
retrieving revision 1.1.1.2
retrieving revision 1.6
diff -c -r1.1.1.2 -r1.6
*** ip_mroute.c	2000/04/25 00:37:11	1.1.1.2
--- ip_mroute.c	2000/10/05 21:19:52	1.6
***************
*** 10,15 ****
--- 10,16 ----
   * Modified by Ajit Thyagarajan, PARC, August 1993
   * Modified by Bill Fenner, PARC, April 1994
   * Modified by Charles M. Hannum, NetBSD, May 1995.
+  * Modified by Jason R. Thorpe, Zembu Labs, October 2000.
   *
   * MROUTING Revision: 1.2
   */
***************
*** 97,103 ****
--- 98,106 ----
  static int get_version __P((struct mbuf *));
  static int set_assert __P((struct mbuf *));
  static int get_assert __P((struct mbuf *));
+ static int oadd_vif __P((struct mbuf *));
  static int add_vif __P((struct mbuf *));
+ static int add_vif_common __P((struct vifctl *, struct ifnet *));
  static int del_vif __P((struct mbuf *));
  static void update_mfc __P((struct mfcctl *, struct mfc *));
  static void expire_mfc __P((struct mfc *));
***************
*** 115,121 ****
  static int ip_mdq __P((struct mbuf *, struct ifnet *, struct mfc *));
  #endif
  static void phyint_send __P((struct ip *, struct vif *, struct mbuf *));
- static void encap_send __P((struct ip *, struct vif *, struct mbuf *));
  static void tbf_control __P((struct vif *, struct mbuf *, struct ip *,
  			     u_int32_t));
  static void tbf_queue __P((struct vif *, struct mbuf *));
--- 118,123 ----
***************
*** 138,177 ****
  struct ifnet multicast_decap_if[MAXVIFS];
  #endif
  
- #define	ENCAP_TTL	64
- #define	ENCAP_PROTO	IPPROTO_IPIP	/* 4 */
- 
- /* prototype IP hdr for encapsulated packets */
- struct ip multicast_encap_iphdr = {
- #if BYTE_ORDER == LITTLE_ENDIAN
- 	sizeof(struct ip) >> 2, IPVERSION,
- #else
- 	IPVERSION, sizeof(struct ip) >> 2,
- #endif
- 	0,				/* tos */
- 	sizeof(struct ip),		/* total length */
- 	0,				/* id */
- 	0,				/* frag offset */
- 	ENCAP_TTL, ENCAP_PROTO,	
- 	0,				/* checksum */
- };
- 
  /*
   * Private variables.
   */
  static vifi_t	   numvifs = 0;
- static int have_encap_tunnel = 0;
  
  static struct callout expire_upcalls_ch;
  
  /*
-  * one-back cache used by mrt_ipip_input to locate a tunnel's vif
-  * given a datagram's src ip address.
-  */
- static struct in_addr last_encap_src;
- static struct vif *last_encap_vif;
- 
- /*
   * whether or not special PIM assert processing is enabled.
   */
  static int pim_assert;
--- 140,153 ----
***************
*** 250,255 ****
--- 226,234 ----
  		case MRT_DONE:
  			error = ip_mrouter_done();
  			break;
+ 		case OMRT_ADD_VIF:
+ 			error = oadd_vif(*m);
+ 			break;
  		case MRT_ADD_VIF:
  			error = add_vif(*m);
  			break;
***************
*** 444,450 ****
  	/* Clear out all the vifs currently in use. */
  	for (vifi = 0; vifi < numvifs; vifi++) {
  		vifp = &viftable[vifi];
! 		if (!in_nullhost(vifp->v_lcl_addr))
  			reset_vif(vifp);
  	}
  
--- 423,429 ----
  	/* Clear out all the vifs currently in use. */
  	for (vifi = 0; vifi < numvifs; vifi++) {
  		vifp = &viftable[vifi];
! 		if (vifp->v_ifp != NULL)
  			reset_vif(vifp);
  	}
  
***************
*** 469,477 ****
  	free(mfchashtbl, M_MRTABLE);
  	mfchashtbl = 0;
  	
- 	/* Reset de-encapsulation cache. */
- 	have_encap_tunnel = 0;
- 	
  	ip_mrouter = 0;
  	
  	splx(s);
--- 448,453 ----
***************
*** 527,554 ****
  static struct sockaddr_in sin = { sizeof(sin), AF_INET };
  
  /*
!  * Add a vif to the vif table
   */
  static int
! add_vif(m)
  	struct mbuf *m;
  {
! 	struct vifctl *vifcp;
! 	struct vif *vifp;
  	struct ifaddr *ifa;
  	struct ifnet *ifp;
! 	struct ifreq ifr;
! 	int error, s;
! 	
! 	if (m == 0 || m->m_len < sizeof(struct vifctl))
  		return (EINVAL);
  
! 	vifcp = mtod(m, struct vifctl *);
  	if (vifcp->vifc_vifi >= MAXVIFS)
  		return (EINVAL);
  
! 	vifp = &viftable[vifcp->vifc_vifi];
! 	if (!in_nullhost(vifp->v_lcl_addr))
  		return (EADDRINUSE);
  	
  	/* Find the interface with an address in AF_INET family. */
--- 503,534 ----
  static struct sockaddr_in sin = { sizeof(sin), AF_INET };
  
  /*
!  * Add a vif to the vif table.  This supports the older,
!  * IP address-based ioctl.
   */
  static int
! oadd_vif(m)
  	struct mbuf *m;
  {
! 	struct ovifctl *vifcp;
  	struct ifaddr *ifa;
  	struct ifnet *ifp;
! 
! 	if (m == 0 || m->m_len < sizeof(struct ovifctl))
  		return (EINVAL);
  
! 	vifcp = mtod(m, struct ovifctl *);
  	if (vifcp->vifc_vifi >= MAXVIFS)
  		return (EINVAL);
  
! 	/*
! 	 * Tunnel vifs are deprecated.  Do not allow them
! 	 * to be added.
! 	 */
! 	if (vifcp->vifc_flags & (OVIFF_TUNNEL|OVIFF_SRCRT))
! 		return (EINVAL);
! 
! 	if (viftable[vifcp->vifc_vifi].v_ifp != NULL)
  		return (EADDRINUSE);
  	
  	/* Find the interface with an address in AF_INET family. */
***************
*** 556,595 ****
  	ifa = ifa_ifwithaddr(sintosa(&sin));
  	if (ifa == 0)
  		return (EADDRNOTAVAIL);
- 	
- 	if (vifcp->vifc_flags & VIFF_TUNNEL) {
- 		if (vifcp->vifc_flags & VIFF_SRCRT) {
- 			log(LOG_ERR, "Source routed tunnels not supported\n");
- 			return (EOPNOTSUPP);
- 		}
  
! 		/* Create a fake encapsulation interface. */
! 		ifp = (struct ifnet *)malloc(sizeof(*ifp), M_MRTABLE, M_WAITOK);
! 		bzero(ifp, sizeof(*ifp));
! 		sprintf(ifp->if_xname, "mdecap%d", vifcp->vifc_vifi);
  
! 		/* Prepare cached route entry. */
! 		bzero(&vifp->v_route, sizeof(vifp->v_route));
  
! 		/* Tell mrt_ipip_input() to start looking at encapsulated packets. */
! 		have_encap_tunnel = 1;
! 	} else {
! 		/* Use the physical interface associated with the address. */
! 		ifp = ifa->ifa_ifp;
  
! 		/* Make sure the interface supports multicast. */
! 		if ((ifp->if_flags & IFF_MULTICAST) == 0)
! 			return (EOPNOTSUPP);
! 
! 		/* Enable promiscuous reception of all IP multicasts. */
! 		satosin(&ifr.ifr_addr)->sin_len = sizeof(struct sockaddr_in);
! 		satosin(&ifr.ifr_addr)->sin_family = AF_INET;
! 		satosin(&ifr.ifr_addr)->sin_addr = zeroin_addr;
! 		error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr);
! 		if (error)
! 			return (error);
  	}
  
  	s = splsoftnet();
  
  	/* Define parameters for the tbf structure. */
--- 536,625 ----
  	ifa = ifa_ifwithaddr(sintosa(&sin));
  	if (ifa == 0)
  		return (EADDRNOTAVAIL);
  
! 	/* Use the physical interface associated with the address. */
! 	ifp = ifa->ifa_ifp;
  
! 	/* Make sure the interface supports multicast. */
! 	if ((ifp->if_flags & IFF_MULTICAST) == 0)
! 		return (EOPNOTSUPP);
  
! 	/*
! 	 * The portion of the vifctl structre that we are interested in
! 	 * is the same between the old and new versions of the strucutre,
! 	 * so we just access it as if it were the new one.
! 	 */
! 	return (add_vif_common((struct vifctl *)vifcp, ifp));
! }
  
! /*
!  * Add a vif to the vif table.  This is the new,
!  * interface-name based version.
!  */
! static int
! add_vif(m)
! 	struct mbuf *m;
! {
! 	struct vifctl *vifcp;
! 	struct ifnet *ifp;
! 	struct ifaddr *ifa;
! 
! 	if (m == 0 || m->m_len < sizeof(struct vifctl))
! 		return (EINVAL);
! 
! 	vifcp = mtod(m, struct vifctl *);
! 	if (vifcp->vifc_vifi >= MAXVIFS)
! 		return (EINVAL);
! 
! 	if (viftable[vifcp->vifc_vifi].v_ifp != NULL)
! 		return (EADDRINUSE);
! 
! 	/* Find the interface. */
! 	vifcp->vifc_ifname[sizeof(vifcp->vifc_ifname) - 1] = '\0';
! 	ifp = ifunit(vifcp->vifc_ifname);
! 	if (ifp == NULL)
! 		return (ENXIO);
! 
! 	/* Make sure the interface has at least one AF_INET address. */
! 	for (ifa = TAILQ_FIRST(&ifp->if_addrlist); ifa != NULL;
! 	     ifa = TAILQ_NEXT(ifa, ifa_list)) {
! 		if (ifa->ifa_addr->sa_family == AF_INET)
! 			break;
  	}
+ 	if (ifa == NULL)
+ 		return (EADDRNOTAVAIL);
+ 
+ 	/* Make sure the interface supports multicast. */
+ 	if ((ifp->if_flags & IFF_MULTICAST) == 0)
+ 		return (EOPNOTSUPP);
  
+ 	/*
+ 	 * The portion of the vifctl structre that we are interested in
+ 	 * is the same between the old and new versions of the strucutre,
+ 	 * so we just access it as if it were the new one.
+ 	 */
+ 	return (add_vif_common(vifcp, ifp));
+ }
+ 
+ int
+ add_vif_common(vifcp, ifp)
+ 	struct vifctl *vifcp;
+ 	struct ifnet *ifp;
+ {
+ 	struct ifreq ifr;
+ 	struct vif *vifp;
+ 	int error, s;
+ 
+ 	vifp = &viftable[vifcp->vifc_vifi];
+ 
+ 	/* Enable promiscuous reception of all IP multicasts. */
+ 	satosin(&ifr.ifr_addr)->sin_len = sizeof(struct sockaddr_in);
+ 	satosin(&ifr.ifr_addr)->sin_family = AF_INET;
+ 	satosin(&ifr.ifr_addr)->sin_addr = zeroin_addr;
+ 	error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr);
+ 	if (error)
+ 		return (error);
+ 
  	s = splsoftnet();
  
  	/* Define parameters for the tbf structure. */
***************
*** 604,611 ****
  	vifp->v_threshold = vifcp->vifc_threshold;
  	/* scaling up here allows division by 1024 in critical code */
  	vifp->v_rate_limit = vifcp->vifc_rate_limit * 1024 / 1000;
- 	vifp->v_lcl_addr = vifcp->vifc_lcl_addr;
- 	vifp->v_rmt_addr = vifcp->vifc_rmt_addr;
  	vifp->v_ifp = ifp;
  	/* Initialize per vif pkt counters. */
  	vifp->v_pkt_in = 0;
--- 634,639 ----
***************
*** 621,637 ****
  #endif /* RSVP_ISI */
  
  	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 %x, %s %x, thresh %x, rate %d\n",
  		    vifcp->vifc_vifi, 
! 		    ntohl(vifcp->vifc_lcl_addr.s_addr),
! 		    (vifcp->vifc_flags & VIFF_TUNNEL) ? "rmtaddr" : "mask",
! 		    ntohl(vifcp->vifc_rmt_addr.s_addr),
  		    vifcp->vifc_threshold,
  		    vifcp->vifc_rate_limit);    
  	
--- 649,664 ----
  #endif /* RSVP_ISI */
  
  	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, interface %s, thresh %x, rate %d\n",
  		    vifcp->vifc_vifi, 
! 		    ifp->if_xname,
  		    vifcp->vifc_threshold,
  		    vifcp->vifc_rate_limit);    
  	
***************
*** 653,671 ****
  		m_freem(m);
  	}
  
! 	if (vifp->v_flags & VIFF_TUNNEL) {
! 		free(vifp->v_ifp, M_MRTABLE);
! 		if (vifp == last_encap_vif) {
! 			last_encap_vif = 0;
! 			last_encap_src = zeroin_addr;
! 		}
! 	} else {
! 		satosin(&ifr.ifr_addr)->sin_len = sizeof(struct sockaddr_in);
! 		satosin(&ifr.ifr_addr)->sin_family = AF_INET;
! 		satosin(&ifr.ifr_addr)->sin_addr = zeroin_addr;
! 		ifp = vifp->v_ifp;
! 		(*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
! 	}
  	bzero((caddr_t)vifp, sizeof(*vifp));
  }
  
--- 680,691 ----
  		m_freem(m);
  	}
  
! 	satosin(&ifr.ifr_addr)->sin_len = sizeof(struct sockaddr_in);
! 	satosin(&ifr.ifr_addr)->sin_family = AF_INET;
! 	satosin(&ifr.ifr_addr)->sin_addr = zeroin_addr;
! 	ifp = vifp->v_ifp;
! 	(*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
! 
  	bzero((caddr_t)vifp, sizeof(*vifp));
  }
  
***************
*** 689,695 ****
  		return (EINVAL);
  
  	vifp = &viftable[*vifip];
! 	if (in_nullhost(vifp->v_lcl_addr))
  		return (EADDRNOTAVAIL);
  	
  	s = splsoftnet();
--- 709,715 ----
  		return (EINVAL);
  
  	vifp = &viftable[*vifip];
! 	if (vifp->v_ifp == NULL)
  		return (EADDRNOTAVAIL);
  	
  	s = splsoftnet();
***************
*** 698,704 ****
  	
  	/* Adjust numvifs down */
  	for (vifi = numvifs; vifi > 0; vifi--)
! 		if (!in_nullhost(viftable[vifi-1].v_lcl_addr))
  			break;
  	numvifs = vifi;
  	
--- 718,724 ----
  	
  	/* Adjust numvifs down */
  	for (vifi = numvifs; vifi > 0; vifi--)
! 		if (viftable[vifi - 1].v_ifp != NULL)
  			break;
  	numvifs = vifi;
  	
***************
*** 999,1007 ****
  	    ip->ip_ttl++;	/* compensate for -1 in *_send routines */
  	if (rsvpdebug && ip->ip_p == IPPROTO_RSVP) {
  	    vifp = viftable + vifi;
! 	    printf("Sending IPPROTO_RSVP from %x to %x on vif %d (%s%s)\n",
  		ntohl(ip->ip_src), ntohl(ip->ip_dst), vifi,
- 		(vifp->v_flags & VIFF_TUNNEL) ? "tunnel on " : "",
  		vifp->v_ifp->if_xname);
  	}
  	return (ip_mdq(m, ifp, (struct mfc *)0, vifi));
--- 1019,1026 ----
  	    ip->ip_ttl++;	/* compensate for -1 in *_send routines */
  	if (rsvpdebug && ip->ip_p == IPPROTO_RSVP) {
  	    vifp = viftable + vifi;
! 	    printf("Sending IPPROTO_RSVP from %x to %x on vif %d (%s)\n",
  		ntohl(ip->ip_src), ntohl(ip->ip_dst), vifi,
  		vifp->v_ifp->if_xname);
  	}
  	return (ip_mdq(m, ifp, (struct mfc *)0, vifi));
***************
*** 1234,1239 ****
--- 1253,1259 ----
      vifi_t xmt_vif;
  #endif /* RSVP_ISI */
  {
+     struct in_ifaddr *ia;
      struct ip  *ip = mtod(m, struct ip *);
      vifi_t vifi;
      struct vif *vifp;
***************
*** 1244,1255 ****
   * input, they shouldn't get counted on output, so statistics keeping is
   * seperate.
   */
! #define MC_SEND(ip,vifp,m) {                             \
!                 if ((vifp)->v_flags & VIFF_TUNNEL)	 \
!                     encap_send((ip), (vifp), (m));       \
!                 else                                     \
!                     phyint_send((ip), (vifp), (m));      \
! }
  
  #ifdef RSVP_ISI
      /*
--- 1264,1270 ----
   * input, they shouldn't get counted on output, so statistics keeping is
   * seperate.
   */
! #define MC_SEND(ip,vifp,m)	phyint_send((ip), (vifp), (m))
  
  #ifdef RSVP_ISI
      /*
***************
*** 1280,1287 ****
  	 * interface (and not a tunnel), send a message to the routing daemon.
  	 */
  	if (pim_assert && rt->mfc_ttls[vifi] &&
! 		(ifp->if_flags & IFF_BROADCAST) &&
! 		!(viftable[vifi].v_flags & VIFF_TUNNEL)) {
  	    struct mbuf *mm;
  	    struct igmpmsg *im;
  	    int hlen = ip->ip_hl << 2;
--- 1295,1301 ----
  	 * interface (and not a tunnel), send a message to the routing daemon.
  	 */
  	if (pim_assert && rt->mfc_ttls[vifi] &&
! 		(ifp->if_flags & IFF_BROADCAST)) {
  	    struct mbuf *mm;
  	    struct igmpmsg *im;
  	    int hlen = ip->ip_hl << 2;
***************
*** 1315,1321 ****
      }
  
      /* If I sourced this packet, it counts as output, else it was input. */
!     if (in_hosteq(ip->ip_src, viftable[vifi].v_lcl_addr)) {
  	viftable[vifi].v_pkt_out++;
  	viftable[vifi].v_bytes_out += plen;
      } else {
--- 1329,1336 ----
      }
  
      /* If I sourced this packet, it counts as output, else it was input. */
!     INADDR_TO_IA(ip->ip_src, ia);
!     if (ia != NULL) {
  	viftable[vifi].v_pkt_out++;
  	viftable[vifi].v_bytes_out += plen;
      } else {
***************
*** 1383,1529 ****
  		tbf_control(vifp, mb_copy, mtod(mb_copy, struct ip *), ip->ip_len);
  }
  
- static void
- encap_send(ip, vifp, m)
- 	struct ip *ip;
- 	struct vif *vifp;
- 	struct mbuf *m;
- {
- 	struct mbuf *mb_copy;
- 	struct ip *ip_copy;
- 	int i, len = ip->ip_len + sizeof(multicast_encap_iphdr);
- 
- 	/*
- 	 * copy the old packet & pullup it's IP header into the
- 	 * new mbuf so we can modify it.  Try to fill the new
- 	 * mbuf since if we don't the ethernet driver will.
- 	 */
- 	MGETHDR(mb_copy, M_DONTWAIT, MT_DATA);
- 	if (mb_copy == 0)
- 		return;
- 	mb_copy->m_data += max_linkhdr;
- 	mb_copy->m_pkthdr.len = len;
- 	mb_copy->m_len = sizeof(multicast_encap_iphdr);
- 	
- 	if ((mb_copy->m_next = m_copy(m, 0, M_COPYALL)) == 0) {
- 		m_freem(mb_copy);
- 		return;
- 	}
- 	i = MHLEN - max_linkhdr;
- 	if (i > len)
- 		i = len;
- 	mb_copy = m_pullup(mb_copy, i);
- 	if (mb_copy == 0)
- 		return;
- 	
- 	/*
- 	 * fill in the encapsulating IP header.
- 	 */
- 	ip_copy = mtod(mb_copy, struct ip *);
- 	*ip_copy = multicast_encap_iphdr;
- 	ip_copy->ip_id = htons(ip_id++);
- 	ip_copy->ip_len = len;
- 	ip_copy->ip_src = vifp->v_lcl_addr;
- 	ip_copy->ip_dst = vifp->v_rmt_addr;
- 	
- 	/*
- 	 * turn the encapsulated IP header back into a valid one.
- 	 */
- 	ip = (struct ip *)((caddr_t)ip_copy + sizeof(multicast_encap_iphdr));
- 	--ip->ip_ttl;
- 	HTONS(ip->ip_len);
- 	HTONS(ip->ip_off);
- 	ip->ip_sum = 0;
- 	mb_copy->m_data += sizeof(multicast_encap_iphdr);
- 	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)
- 		tbf_send_packet(vifp, mb_copy);
- 	else
- 		tbf_control(vifp, mb_copy, ip, ip_copy->ip_len);
- }
- 
  /*
-  * De-encapsulate a packet and feed it back through ip input (this
-  * routine is called whenever IP gets a packet with proto type
-  * ENCAP_PROTO and a local destination address).
-  *
-  * Return 1 if we handled the packet, 0 if we did not.
-  *
-  * Called from encap4_input() in sys/netinet/ip_encap.c.
-  */
- int
- mrt_ipip_input(m, hlen)
- 	struct mbuf *m;
- 	int hlen;
- {
- 	struct ip *ip = mtod(m, struct ip *);
- 	int s;
- 	struct ifqueue *ifq;
- 	struct vif *vifp;
- 
- 	if (!have_encap_tunnel)
- 		return (0);
- 
- 	/*
- 	 * dump the packet if it's not to a multicast destination or if
- 	 * we don't have an encapsulating tunnel with the source.
- 	 * Note:  This code assumes that the remote site IP address
- 	 * uniquely identifies the tunnel (i.e., that this site has
- 	 * at most one tunnel with the remote site).
- 	 */
- 	if (!IN_MULTICAST(((struct ip *)((char *)ip + hlen))->ip_dst.s_addr)) {
- 		++mrtstat.mrts_bad_tunnel;
- 		return (0);
- 	}
- 
- 	if (!in_hosteq(ip->ip_src, last_encap_src)) {
- 		struct vif *vife;
- 	
- 		vifp = viftable;
- 		vife = vifp + numvifs;
- 		for (; vifp < vife; vifp++)
- 			if (vifp->v_flags & VIFF_TUNNEL &&
- 			    in_hosteq(vifp->v_rmt_addr, ip->ip_src))
- 				break;
- 		if (vifp == vife) {
- 			mrtstat.mrts_cant_tunnel++; /*XXX*/
- 			if (mrtdebug)
- 				log(LOG_DEBUG,
- 				    "ip_mforward: no tunnel with %x\n",
- 				    ntohl(ip->ip_src.s_addr));
- 			return (0);
- 		}
- 		last_encap_vif = vifp;
- 		last_encap_src = ip->ip_src;
- 	} else
- 		vifp = last_encap_vif;
- 
- 	m->m_data += hlen;
- 	m->m_len -= hlen;
- 	m->m_pkthdr.len -= hlen;
- 	m->m_pkthdr.rcvif = vifp->v_ifp;
- 	ifq = &ipintrq;
- 	s = splimp();
- 	if (IF_QFULL(ifq)) {
- 		IF_DROP(ifq);
- 		m_freem(m);
- 	} else {
- 		IF_ENQUEUE(ifq, m);
- 		/*
- 		 * normally we would need a "schednetisr(NETISR_IP)"
- 		 * here but we were called by ip_input and it is going
- 		 * to loop back & try to dequeue the packet we just
- 		 * queued as soon as we return so we avoid the
- 		 * unnecessary software interrrupt.
- 		 */
- 	}
- 	splx(s);
- 	return (1);
- }
- 
- /*
   * Token bucket filter module
   */
  static void
--- 1398,1404 ----
***************
*** 1683,1721 ****
  	struct vif *vifp;
  	struct mbuf *m;
  {
  	int error;
  	int s = splsoftnet();
- 
- 	if (vifp->v_flags & VIFF_TUNNEL) {
- 		/* If tunnel options */
- #ifdef IPSEC
- 		/* Don't lookup socket in forwading case */
- 		ipsec_setsocket(m, NULL);
- #endif
- 		ip_output(m, (struct mbuf *)0, &vifp->v_route,
- 			  IP_FORWARDING, (struct ip_moptions *)0);
- 	} else {
- 		/* if physical interface option, extract the options and then send */
- 		struct ip_moptions imo;
  
! 		imo.imo_multicast_ifp = vifp->v_ifp;
! 		imo.imo_multicast_ttl = mtod(m, struct ip *)->ip_ttl - 1;
! 		imo.imo_multicast_loop = 1;
  #ifdef RSVP_ISI
! 		imo.imo_multicast_vif = -1;
  #endif
  
  #ifdef IPSEC
! 		/* Don't lookup socket in forwading case */
! 		ipsec_setsocket(m, NULL);
  #endif
! 		error = ip_output(m, (struct mbuf *)0, (struct route *)0,
! 				  IP_FORWARDING|IP_MULTICASTOPTS, &imo);
  
! 		if (mrtdebug & DEBUG_XMIT)
! 			log(LOG_DEBUG, "phyint_send on vif %ld err %d\n",
! 			    (long)(vifp-viftable), error);
! 	}
  	splx(s);
  }
  
--- 1558,1584 ----
  	struct vif *vifp;
  	struct mbuf *m;
  {
+ 	struct ip_moptions imo;
  	int error;
  	int s = splsoftnet();
  
! 	imo.imo_multicast_ifp = vifp->v_ifp;
! 	imo.imo_multicast_ttl = mtod(m, struct ip *)->ip_ttl - 1;
! 	imo.imo_multicast_loop = 1;
  #ifdef RSVP_ISI
! 	imo.imo_multicast_vif = -1;
  #endif
  
  #ifdef IPSEC
! 	/* Don't lookup socket in forwading case */
! 	ipsec_setsocket(m, NULL);
  #endif
! 	error = ip_output(m, (struct mbuf *)0, (struct route *)0,
! 			  IP_FORWARDING|IP_MULTICASTOPTS, &imo);
  
! 	if (mrtdebug & DEBUG_XMIT)
! 		log(LOG_DEBUG, "phyint_send on vif %ld err %d\n",
! 		    (long)(vifp-viftable), error);
  	splx(s);
  }
  
Index: ip_mroute.h
===================================================================
RCS file: /home/cvsfiles/netbsd/src/sys/netinet/ip_mroute.h,v
retrieving revision 1.1.1.1
retrieving revision 1.6
diff -c -r1.1.1.1 -r1.6
*** ip_mroute.h	2000/03/31 20:00:36	1.1.1.1
--- ip_mroute.h	2000/10/05 21:19:52	1.6
***************
*** 7,12 ****
--- 7,13 ----
   * Modified by Steve Deering, Stanford, February 1989.
   * Modified by Ajit Thyagarajan, PARC, August 1993.
   * Modified by Ajit Thyagarajan, PARC, August 1994.
+  * Modified by Jason R. Thorpe, Zembu Labs, October 2000.
   *
   * MROUTING Revision: 1.2
   */
***************
*** 17,33 ****
  #include <sys/queue.h>
  #include <sys/callout.h>
  
  /*
   * Multicast Routing set/getsockopt commands.
   */
  #define	MRT_INIT		100	/* initialize forwarder */
  #define	MRT_DONE		101	/* shut down forwarder */
! #define	MRT_ADD_VIF		102	/* create virtual interface */
  #define	MRT_DEL_VIF		103	/* delete virtual interface */
  #define	MRT_ADD_MFC		104	/* insert forwarding cache entry */
  #define	MRT_DEL_MFC		105	/* delete forwarding cache entry */
  #define	MRT_VERSION		106	/* get kernel version number */
  #define	MRT_ASSERT		107	/* enable PIM assert processing */
  
  
  /*
--- 18,37 ----
  #include <sys/queue.h>
  #include <sys/callout.h>
  
+ #include <net/if.h>
+ 
  /*
   * Multicast Routing set/getsockopt commands.
   */
  #define	MRT_INIT		100	/* initialize forwarder */
  #define	MRT_DONE		101	/* shut down forwarder */
! #define	OMRT_ADD_VIF		102	/* old create virtual interface */
  #define	MRT_DEL_VIF		103	/* delete virtual interface */
  #define	MRT_ADD_MFC		104	/* insert forwarding cache entry */
  #define	MRT_DEL_MFC		105	/* delete forwarding cache entry */
  #define	MRT_VERSION		106	/* get kernel version number */
  #define	MRT_ASSERT		107	/* enable PIM assert processing */
+ #define	MRT_ADD_VIF		108	/* create virtual interface */
  
  
  /*
***************
*** 45,58 ****
  #define	VIFM_COPY(mfrom, mto)		((mto) = (mfrom))
  #define	VIFM_SAME(m1, m2)		((m1) == (m2))
  
! #define	VIFF_TUNNEL	0x1		/* vif represents a tunnel end-point */
! #define	VIFF_SRCRT	0x2		/* tunnel uses IP src routing */
  
  /*
!  * Argument structure for MRT_ADD_VIF.
   * (MRT_DEL_VIF takes a single vifi_t argument.)
   */
! struct vifctl {
  	vifi_t	  vifc_vifi;	    	/* the index of the vif to be added */
  	u_int8_t  vifc_flags;     	/* VIFF_ flags defined below */
  	u_int8_t  vifc_threshold; 	/* min ttl required to forward on vif */
--- 49,68 ----
  #define	VIFM_COPY(mfrom, mto)		((mto) = (mfrom))
  #define	VIFM_SAME(m1, m2)		((m1) == (m2))
  
! #ifdef _KERNEL
! /*
!  * These flags were used for "tunnel" vifs, and are deprecated.  We
!  * rename them to break old source, but keep them around in order
!  * to return sane errors to userland routing daemons.
!  */
! #define	OVIFF_TUNNEL		0x01
! #define	OVIFF_SRCRT		0x02
  
  /*
!  * Argument structure for OMRT_ADD_VIF.
   * (MRT_DEL_VIF takes a single vifi_t argument.)
   */
! struct ovifctl {
  	vifi_t	  vifc_vifi;	    	/* the index of the vif to be added */
  	u_int8_t  vifc_flags;     	/* VIFF_ flags defined below */
  	u_int8_t  vifc_threshold; 	/* min ttl required to forward on vif */
***************
*** 60,65 ****
--- 70,88 ----
  	struct	  in_addr vifc_lcl_addr;/* local interface address */
  	struct	  in_addr vifc_rmt_addr;/* remote address (tunnels only) */
  };
+ #endif /* _KERNEL */
+ 
+ /*
+  * Argument structure for MRT_ADD_VIF.
+  * (MRT_DEL_VIF takes a single vifi_t argument.)
+  */
+ struct vifctl {
+ 	vifi_t    vifc_vifi;		/* the index of the vif to be added */
+ 	u_int8_t  vifc_flags;		/* VIFF_ flags */
+ 	u_int8_t  vifc_threshold;	/* min ttl required to forward on vif */
+ 	u_int32_t vifc_rate_limit;	/* max rate */
+ 	char      vifc_ifname[IFNAMSIZ];/* interface name */
+ };
  
  /*
   * Argument structure for MRT_ADD_MFC and MRT_DEL_MFC.
***************
*** 130,143 ****
  	u_int8_t  v_flags;		/* VIFF_ flags defined above */
  	u_int8_t  v_threshold;		/* min ttl required to forward on vif */
  	u_int32_t v_rate_limit;		/* max rate */
- 	struct	  in_addr v_lcl_addr;	/* local interface address */
- 	struct	  in_addr v_rmt_addr;	/* remote address (tunnels only) */
  	struct	  ifnet *v_ifp;		/* pointer to interface */
  	u_long	  v_pkt_in;		/* # pkts in on interface */
  	u_long	  v_pkt_out;		/* # pkts out on interface */
  	u_long	  v_bytes_in;		/* # bytes in on interface */
  	u_long	  v_bytes_out;		/* # bytes out on interface */
- 	struct	  route v_route;	/* cached route if this is a tunnel */
  	struct	  callout v_repq_ch;	/* for tbf_reprocess_q() */
  #ifdef RSVP_ISI
  	int	  v_rsvp_on;		/* # RSVP listening on this vif */
--- 153,163 ----
***************
*** 218,224 ****
  #else
  int ip_mforward __P((struct mbuf *, struct ifnet *));
  #endif
- int mrt_ipip_input __P((struct mbuf *, int));
  
  #endif /* _KERNEL */
  
--- 238,243 ----

--BOKacYhQ+x31HxR3--