예제 #1
0
void
mpls_input(struct mbuf *m)
{
	struct ifnet *ifp = m->m_pkthdr.rcvif;
	struct sockaddr_mpls *smpls;
	struct sockaddr_mpls sa_mpls;
	struct shim_hdr	*shim;
	struct rtentry *rt = NULL;
	struct rt_mpls *rt_mpls;
	u_int8_t ttl;
	int i, s, hasbos;

	if (!ISSET(ifp->if_xflags, IFXF_MPLS)) {
		m_freem(m);
		return;
	}

	/* drop all broadcast and multicast packets */
	if (m->m_flags & (M_BCAST | M_MCAST)) {
		m_freem(m);
		return;
	}

	if (m->m_len < sizeof(*shim))
		if ((m = m_pullup(m, sizeof(*shim))) == NULL)
			return;

	shim = mtod(m, struct shim_hdr *);

#ifdef MPLS_DEBUG
	printf("mpls_input: iface %s label=%d, ttl=%d BoS %d\n",
	    ifp->if_xname, MPLS_LABEL_GET(shim->shim_label),
	    MPLS_TTL_GET(shim->shim_label),
	    MPLS_BOS_ISSET(shim->shim_label));
#endif

	/* check and decrement TTL */
	ttl = ntohl(shim->shim_label & MPLS_TTL_MASK);
	if (ttl-- <= 1) {
		/* TTL exceeded */
		m = mpls_do_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 0);
		if (m == NULL)
			return;
		shim = mtod(m, struct shim_hdr *);
		ttl = ntohl(shim->shim_label & MPLS_TTL_MASK);
	}
예제 #2
0
/*
 * Original (hw independent) Link layer output routine is wrapped by 
 * mpls_output, if focussed Link layer interface remains in MPLS enabled 
 * state. Original output routine is hooked by mpls_ifinfo{} and called 
 * by mpls_output.
 *
 * Any by protocol layer above transmitted mbuf(9) containing Protocol 
 * Data Uniit (pdu) must pass MPLS layer, if for transmission used interface
 * on link-layer remains in MPLS enabled state. 
 * 
 * I/O Path, IPv4:
 *
 *              rip_input() +{ socket layer }+ rip_output()
 *                         /                  \
 *                        /                    \
 *      +-->+ ip_input() +-->+ ip_forward() +-->+ ip_output()
 *     /     \                                   \
 *    /       \                                   +
 *   +         +<------+                          |
 *   |                  \                         v 
 *   + mpls_input() +--->+ mpls_forward() +------>+ mpls_output()			
 *   |\                                          /|
 *   | \                               +<-------+ |
 *   |  \                             /           |
 *   |   +<-----------+ if_simloop() +<-----------+ if_output()
 *   |                                            |
 *   + if_input()                                 |
 *   A                                            |
 *   |                                            V
 *
 */
int
mpls_output(struct ifnet *ifp, struct mbuf *m, 
		const struct sockaddr *dst, struct route *ro)
{	
	struct mpls_ifinfo *mii;
	struct mpls_ro mplsroute;
	struct mpls_ro *mro;
	struct sockaddr *gw;
	
	int error = 0;
	
#ifdef MPLS_DEBUG
	struct shim_hdr *shim;
#endif /* MPLS_DEBUG */ 	
	
	if ((ifp->if_flags & IFF_MPLS) == 0) {
/*
 * Any pdu originates MPLS-layer are looped back into its 
 * domain, if for transmission used interface cannot accept 
 * by MPLS-layer processed pdu.
 *
 * See net/if_ethersubr.c and net/if_loop.c for further details.
 */
		if (dst->sa_family == AF_MPLS) 
			if_simloop(ifp, m, dst->sa_family, 0);
		else 
			error = (*ifp->if_output)(ifp, m, dst, ro);
		goto out;
	}	
	IF_AFDATA_RLOCK(ifp);
	mii = MPLS_IFINFO(ifp);
	IF_AFDATA_RUNLOCK(ifp);
	
	mro = &mplsroute;
	bzero(mro, sizeof(*mro));
	
	if (ro == NULL) 
		ro = (struct route *)mro;	

	if (ro->ro_rt != NULL) {
/*
 * If route exists, three cases are considered:
 * 
 *  (a) held route denotes fastpath. 
 *  (b) held route denotes ilm,
 *
 * or
 *  
 *  (c) held route originates not AF_MPLS domain.
 */
		if (ro->ro_rt->rt_flags & RTF_MPE) { 
			gw = ro->ro_rt->rt_gateway;
			
			if ((m = mpls_encap(m, gw, mro)) == NULL) {
				error = ECONNABORTED;
				goto done;
			}
			gw = (struct sockaddr *)&mro->mro_gw;
		} else
			gw = (struct sockaddr *)dst;		
	} else
		gw = (struct sockaddr *)dst;
	
	if (m->m_flags & M_MPLS) {
/*
 * Bypass tagging, if mbuf(9) was cached by MPLS_ARP.
 */
		m->m_flags &= ~M_MPLS;
	} else if (mii->mii_nhlfe != NULL) {
/*
 * Otherwise, mbuf(9) must pass mpls_encap, if 
 * interface is bound by MPLS label binding on
 * per-interface MPLS label space.  
 */	
		mro->mro_ifa = mii->mii_nhlfe;
		gw = mro->mro_ifa->ifa_dstaddr;
/*
 * Per interface MPLS label space.
 */					
		if ((m = mpls_encap(m, gw, mro)) == NULL) {
			error = ECONNABORTED;
			goto done;
		}
		gw = (struct sockaddr *)&mro->mro_gw;
	}
	
	if (gw->sa_family == AF_MPLS) {
/* 
 * Defines iap for pfil(9) processing.
 */
		if (PFIL_HOOKED(&V_inet_pfil_hook)
#ifdef INET6
	    	|| PFIL_HOOKED(&V_inet6_pfil_hook)
#endif
	    ) {		
			if (mpls_pfil(&m, ifp, PFIL_OUT) != 0)
				goto done;
				
			if (m == NULL)
				goto done;
		}
		
#ifdef MPLS_DEBUG
	shim = mtod(m, struct shim_hdr *);
	(void)printf("%s: on %s label %d ttl %d bos %d\n", 
		__func__, ifp->if_xname, 
		MPLS_LABEL_GET(shim->shim_label), 
		MPLS_TTL_GET(shim->shim_label), 
		MPLS_BOS(shim->shim_label));
#endif /* MPLS_DEBUG */	

		m->m_flags &= ~(M_BCAST|M_MCAST);
	}
	error = (*mii->mii_output)(ifp, m, gw, ro);
done:	
	if (mro != NULL)
		mpls_rtfree(mro);
out:	
	return (error);
}