kern/179473: Source code contribution of implementation about virtual ethernet interface

Henning Matyschok henning.matyschok at stud.fh-flensburg.de
Thu Jun 20 00:40:02 UTC 2013


The following reply was made to PR kern/179473; it has been noted by GNATS.

From: "Henning Matyschok" <henning.matyschok at stud.fh-flensburg.de>
To: bug-followup at freebsd.org, henning.matyschok at stud.fh-flensburg.de
Cc:  
Subject: Re: kern/179473: Source code contribution of implementation about
 virtual ethernet interface
Date: Thu, 20 Jun 2013 00:34:17 -0000

 ------------yPGQsOt2uvF1CxHxvIlgW8
 Content-Type: text/plain; charset=us-ascii; format=flowed; delsp=yes
 Content-Transfer-Encoding: 7bit
 
 I'm excusing for my bad english.
 ------------yPGQsOt2uvF1CxHxvIlgW8
 Content-Disposition: attachment; filename=if_veth.c.txt
 Content-Type: text/plain; name=if_veth.c.txt
 Content-Transfer-Encoding: 7bit
 
 /*-
  * Copyright (c) 2013 Henning Matyschok
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  * Copyright (c) 1982, 1989, 1993
  *	The Regents of the University of California.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
  * 4. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
  */
 #include <sys/param.h>
 #include <sys/kernel.h>
 #include <sys/module.h>
 #include <sys/libkern.h>
 #include <sys/socket.h> 
 #include <sys/sockio.h>
  
 #include <net/if.h>
 #include <net/if_clone.h>
 #include <net/if_media.h>
 #include <net/if_types.h>
 #include <net/netisr.h>
 #include <net/if_var.h>
 #include <net/ethernet.h>
 #include <net/if_bridgevar.h>
 #include <net/if_vlan_var.h>
 #include <net/if_dl.h>
 #include <net/if_arp.h>
 #include <net/bpf.h>
  
 #include <netinet/in.h>
 #include <netinet/in_var.h>
 #include <netinet/ip_carp.h>
  
 #ifdef MAC
 #include <security/mac/mac_framework.h>
 #endif /* MAC */
  
 static const uint8_t ether_bcast_lla[ETHER_ADDR_LEN] =
 	{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
  
 /* if_lagg(4) entry point. */
 extern struct mbuf	*(*lagg_input_p)(struct ifnet *, struct mbuf *); 
  
 /* ng_ether(4) entry point. */
 extern	void	(*ng_ether_input_p)(struct ifnet *, struct mbuf **);
  
 /*
  * Declaration of reduced struct bridge_softc is needed to identify 
  * bridge(4) describing ifnet structure on the fly, when veth_start()
  * may called. See net/if_bridge.c and net/if_var.h for further 
  * details.
  */
 struct bridge_softc {
 	struct ifnet	*sc_ifp; 	
 };
  
 #define VETHNAME	"veth"
  
 struct veth_softc {
 	struct ifnet	*sc_ifp;
 	LIST_ENTRY(veth_softc) veth_list;
 	struct mtx	sc_mtx;	
 #define	VETH_LOCK_INIT(sc)	mtx_init(&(sc)->sc_mtx, "veth softc",	\
 				     NULL, MTX_DEF)
 #define	VETH_LOCK_DESTROY(sc)	mtx_destroy(&(sc)->sc_mtx)
 #define	VETH_LOCK(sc)		mtx_lock(&(sc)->sc_mtx)
 #define	VETH_UNLOCK(sc)		mtx_unlock(&(sc)->sc_mtx)
 #define	VETH_LOCK_ASSERT(sc)	mtx_assert(&(sc)->sc_mtx, MA_OWNED)	
 	/* Fake information about used transmission media. */
 	struct ifmedia	sc_ifm;	
 	int	sc_status;
 };
  
 static LIST_HEAD(, veth_softc) veth_list;
  
 static struct mtx veth_mtx;
 static MALLOC_DEFINE(M_VETH, VETHNAME, "Virtual ethernet interface");
  
 /* Ifc cloner specific subr.  */
 static int	veth_clone_create(struct if_clone *, int, caddr_t);
 static void	veth_clone_destroy(struct ifnet *);
  
 IFC_SIMPLE_DECLARE(veth, 0);
  
 /* Interface specific methods. */
 static void	veth_init(void *);
 static void	veth_input_internal(struct ifnet *, struct mbuf *);
 static void	veth_input(struct ifnet *, struct mbuf *);
 static int	veth_media_change(struct ifnet *);
 static void	veth_media_status(struct ifnet *ifp, struct ifmediareq *);
 static int	veth_ioctl(struct ifnet *, u_long, caddr_t);
 static void	veth_start(struct ifnet *);
 static void	veth_stop(struct ifnet *, int);
  
 /* See net/netisr.h for further deteils. */
 #define NETISR_VETH	13
 static void	veth_nh_input(struct mbuf *);
  
 /* Netisr handler definition. */
 static struct netisr_handler veth_nh = {
 	.nh_name = VETHNAME,
 	.nh_handler = veth_nh_input,
 	.nh_proto = NETISR_VETH,
 	.nh_policy = NETISR_POLICY_SOURCE,
 	.nh_dispatch = NETISR_DISPATCH_DIRECT,
 };
  
 /*
  * Module event handler.
  */
 static int
 veth_mod_event(module_t mod, int event, void *data)
 {
 	int error = 0;
  
 	switch (event) {
 	case MOD_LOAD:
  
 		mtx_init(&veth_mtx, "if_veth", NULL, MTX_DEF);
 		netisr_register(&veth_nh);
 		if_clone_attach(&veth_cloner);
 		break;
 	case MOD_UNLOAD:	
  
 		if_clone_detach(&veth_cloner);
 		netisr_unregister(&veth_nh);
 		mtx_destroy(&veth_mtx);
 		break;
 	default:
 		error = EOPNOTSUPP;
 	}
  
 	return(error);
 } 
  
 static moduledata_t veth_mod = {
 	"if_veth",
 	veth_mod_event,
 	0
 };
 DECLARE_MODULE(if_veth, veth_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
  
 /*
  * Instantiates veth interface.
  */
 static int
 veth_clone_create(struct if_clone *ifc, int unit, caddr_t data)
 {
 	struct veth_softc *sc;
 	struct ifnet *ifp;
 	uint32_t randval;
 	uint8_t	lla[ETHER_ADDR_LEN];
  
 	sc = malloc(sizeof(struct veth_softc), M_VETH, M_WAITOK|M_ZERO);
 	ifp = sc->sc_ifp = if_alloc(IFT_ETHER);
 	if (ifp == NULL) {
 		free(sc, M_VETH);
 		return(ENOSPC);
 	}
  
 	VETH_LOCK_INIT(sc);
 	ifp->if_softc = sc;
  
 	if_initname(ifp, ifc->ifc_name, unit);
  
 	/* Generates lla with randomized value. */
 	lla[0] = 0x0;
 	randval = arc4random();
 	memcpy(&lla[1], &randval, sizeof(uint32_t));
 	lla[5] = (uint8_t)unit; /* Interface major number */
  
 	ether_ifattach(ifp, lla);
  
 	ifp->if_init = veth_init;
 	ifp->if_input = veth_input;
 	ifp->if_ioctl = veth_ioctl;
 	ifp->if_start = veth_start;
  
 	ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_JUMBO_MTU;
 	ifp->if_capenable = IFCAP_VLAN_MTU | IFCAP_JUMBO_MTU;
 	ifp->if_flags = (IFF_SIMPLEX|IFF_BROADCAST|IFF_MULTICAST);
 	ifp->if_snd.ifq_maxlen = ifqmaxlen;
  
 	ifmedia_init(&sc->sc_ifm, 0, veth_media_change, veth_media_status);
 	ifmedia_add(&sc->sc_ifm, IFM_ETHER|IFM_1000_T|IFM_FDX, 0, NULL);
 	ifmedia_set(&sc->sc_ifm, IFM_ETHER|IFM_1000_T|IFM_FDX);
  
 	sc->sc_status = IFM_AVALID;
 	ifp->if_baudrate = 0;
  
 	mtx_lock(&veth_mtx);
 	LIST_INSERT_HEAD(&veth_list, sc, veth_list);
 	mtx_unlock(&veth_mtx);
 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
  
 	return(0);
 }
  
 /*
  * Destroys veth interface.
  */
 static void
 veth_clone_destroy(struct ifnet *ifp)
 {
 	struct veth_softc *sc;	
 	sc = ifp->if_softc;	
  
 	mtx_lock(&veth_mtx);
 	veth_stop(ifp, 1);
 	ifp->if_flags &= ~IFF_UP;			
 	LIST_REMOVE(sc, veth_list);
 	ether_ifdetach(ifp);
 	VETH_LOCK_DESTROY(sc);
  
 	mtx_unlock(&veth_mtx);
 	free(sc, M_VETH);
 }
  
 static int
 veth_media_change(struct ifnet *ifp)
 {
 	return(0);
 }
  
 static void
 veth_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
 {
 	ifmr->ifm_status = IFM_AVALID|IFM_ACTIVE;
 	ifmr->ifm_active = IFM_ETHER|IFM_1000_T|IFM_FDX;
 }
  
 /*
  * Handles ioctl requests. Media types can't changed, 
  * this is a virtual ethernet interface.
  */
 static int
 veth_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
 {
 	struct veth_softc *sc = ifp->if_softc;	
 	struct ifreq *ifr = (struct ifreq *)data;
 	int error = 0;
  
 	VETH_LOCK(sc);
 	switch (cmd) {
 	case SIOCSIFMTU:
 		if (ifr->ifr_mtu > ETHER_MAX_LEN_JUMBO) {
 			error = EINVAL;
 		} else {
 			ifp->if_mtu = ifr->ifr_mtu;
 		}	
 		break;
 	case SIOCSIFMEDIA:
 	case SIOCGIFMEDIA:
 		error = ifmedia_ioctl(ifp, ifr, &sc->sc_ifm, cmd);
 		break;
 	case SIOCSIFFLAGS:
 	case SIOCADDMULTI:
 	case SIOCDELMULTI:
 		break;
 	case SIOCSIFPHYS:
 		error = EOPNOTSUPP;
 		break;
 	default:
 		error = ether_ioctl(ifp, cmd, data);
 		break;
 	}
 	VETH_UNLOCK(sc);
 	return(error);
 }
  
 /*
  * Initializes veth interface.
  */
 static void
 veth_init(void *xsc)
 {
 	struct veth_softc *sc;
 	struct ifnet *ifp;
  
 	sc = (struct veth_softc *)xsc;
 	ifp = sc->sc_ifp;
  
 	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
 		return;
 	}
  
 	VETH_LOCK(sc);
 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
 	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
 	VETH_UNLOCK(sc);
 }
  
 /*
  * Stops veth interface.
  */
 static void
 veth_stop(struct ifnet *ifp, int disable)
 {
 	struct veth_softc *sc;
  
 	sc = ifp->if_softc;
 	VETH_LOCK_ASSERT(sc);
  
 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
 		return;
 	}
 	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
 }	
  
 /*
  * Dispatches transmissions of queued frames to bridge(4) or to
  * itself when bridge(4) forwarded frames to this interface. 
  */
 static void
 veth_start(struct ifnet *ifp)
 {
 	struct mbuf	*m;
 	struct bridge_softc *sc;
 	struct ifnet *bifp;
  
 	ifp->if_drv_flags |= IFF_DRV_OACTIVE;
 	for (;;) {
 		IFQ_DEQUEUE(&ifp->if_snd, m);
 		if (m == NULL) {
 			break;
 		}
  
 		if (ifp->if_bridge) {
 			sc = ifp->if_bridge;
 			bifp = sc->sc_ifp;
  
 			if (m->m_pkthdr.rcvif == NULL) {
 				m->m_pkthdr.rcvif = ifp;
                 ETHER_BPF_MTAP(ifp, m);
 				ifp->if_obytes += m->m_pkthdr.len;
 				ifp->if_opackets++;
 				(bifp->if_transmit)(bifp, m);
 			} else if (m->m_pkthdr.rcvif == ifp) {
 				m_freem(m);
 			} else {
 				(ifp->if_input)(ifp, m);	
 			} 
 		} else {
 			m_freem(m);
 		}
 	}
  
 	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
 }
  
 /*
  * Handles input of frames. This method is derived 
  * from ether_input_internal() where its implementation 
  * remains in net/if_ethersubr.c. 
  */
 static void
 veth_input_internal(struct ifnet *ifp, struct mbuf *m)
 {
 	struct ether_header *eh;
 	uint16_t type;
  
 	if ((ifp->if_flags & IFF_UP) == 0) {
 		goto bad;
 	}
  
 	if ((m->m_flags & M_PKTHDR) == 0) {
 		goto drop;
 	}
  
 	if (m->m_len < ETHER_HDR_LEN) {
 		m = m_pullup(m, ETHER_HDR_LEN);
 		if (m == NULL) {
 			goto drop;
 		}
 	}
  
 	eh = mtod(m, struct ether_header *);
 	type = ntohs(eh->ether_type);
 	if (m->m_pkthdr.rcvif == NULL) {
 		goto drop;
 	}
  
 	if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
 		if (bcmp(ether_bcast_lla, eh->ether_dhost, 
 			ETHER_ADDR_LEN) == 0) {
 			m->m_flags |= M_BCAST;
 		} else {
 			m->m_flags |= M_MCAST;
 		}
 		ifp->if_imcasts++;
 	}
  
 #ifdef MAC
 	mac_ifnet_create_mbuf(ifp, m);
 #endif /* MAC */
  
 	ETHER_BPF_MTAP(ifp, m);
 	ifp->if_ibytes += m->m_pkthdr.len;
 	ifp->if_ipackets++;
 	if (ifp->if_flags & IFF_MONITOR) {
 		goto drop;
 	}
  
 	if (lagg_input_p) {
 		if (ifp->if_type == IFT_IEEE8023ADLAG) {
 			m = (*lagg_input_p)(ifp, m);
 			if (m != NULL) {
 				ifp = m->m_pkthdr.rcvif;
 			} else { 
 				return;
 			}
 		}
 	}
  
 	if ((m->m_flags & M_VLANTAG) == 0 
 		&& type == ETHERTYPE_VLAN) {
 		struct ether_vlan_header *evl;
  
 		if (m->m_len < sizeof(*evl) 
 		&& (m = m_pullup(m, sizeof(*evl))) == NULL) {
 			goto drop;
 		}
  
 		evl = mtod(m, struct ether_vlan_header *);
 		m->m_pkthdr.ether_vtag = ntohs(evl->evl_tag);
 		m->m_flags |= M_VLANTAG;
  
 		bcopy((char *)evl, (char *)evl + ETHER_VLAN_ENCAP_LEN,
 		    ETHER_HDR_LEN - ETHER_TYPE_LEN);
 		m_adj(m, ETHER_VLAN_ENCAP_LEN);
 	}
  
 	M_SETFIB(m, ifp->if_fib);
  
 	if (ng_ether_input_p) {
 		if (IFP2AC(ifp)->ac_netgraph) {
 			(*ng_ether_input_p)(ifp, &m);
 			if (m == NULL) {
 				return;
 			}
 		}
 	}
  
 	if (ifp->if_carp && (*carp_forus_p)(ifp, eh->ether_dhost)) {
 		m->m_flags &= ~M_PROMISC;
 	} else {
 		if (!ETHER_IS_MULTICAST(eh->ether_dhost) 
 		&& bcmp(IF_LLADDR(ifp), eh->ether_dhost, 
 			ETHER_ADDR_LEN) != 0) {
 			m->m_flags |= M_PROMISC;
     	}
 	}
  
 	ether_demux(ifp, m);
 	return;
 drop:
 	ifp->if_ierrors++;
 bad:
 	m_freem(m);
 }
  
 static void
 veth_nh_input(struct mbuf *m)
 {
 	veth_input_internal(m->m_pkthdr.rcvif, m);
 }
  
 static void
 veth_input(struct ifnet *ifp, struct mbuf *m)
 {
 	netisr_dispatch(NETISR_VETH, m);
 }
 
 ------------yPGQsOt2uvF1CxHxvIlgW8--
 


More information about the freebsd-bugs mailing list