Index: share/man/man4/Makefile =================================================================== --- share/man/man4/Makefile +++ share/man/man4/Makefile @@ -528,6 +528,7 @@ udplite.4 \ ure.4 \ vale.4 \ + vether.4 \ vga.4 \ vge.4 \ viapm.4 \ @@ -714,6 +715,7 @@ MLINKS+=ti.4 if_ti.4 MLINKS+=tun.4 if_tun.4 MLINKS+=ure.4 if_ure.4 +MLINKS+=vether.4 if_vether.4 MLINKS+=vge.4 if_vge.4 MLINKS+=vlan.4 if_vlan.4 MLINKS+=vxlan.4 if_vxlan.4 Index: share/man/man4/vether.4 =================================================================== --- /dev/null +++ share/man/man4/vether.4 @@ -0,0 +1,53 @@ +.\" $OpenBSD: vether.4,v 1.4 2014/01/20 05:07:49 schwarze Exp $ +.\" +.\" Copyright (c) 2009 Theo de Raadt +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.\" $FreeBSD$ +.\" +.Dd $Mdocdate: January 20 2014 $ +.Dt VETHER 4 +.Os +.Sh NAME +.Nm vether +.Nd virtual Ethernet interface +.Sh SYNOPSIS +.Cd "pseudo-device vether" +.Sh DESCRIPTION +The +.Nm +interface simulates a normal Ethernet interface by encapsulating +standard network frames with an Ethernet header, specifically +for use as a member in a +.Xr bridge 4 . +.Pp +To use +.Nm +the administrator needs to configure an address onto the interface +so that packets can be routed to it. +An Ethernet header will be prepended and, if the +.Nm +interface is a member of a +.Xr bridge 4 , +the frame will show up there. +.Sh SEE ALSO +.Xr arp 4 , +.Xr bridge 4 , +.Xr inet 4 , +.Xr inet6 4 , +.Xr netintro 4 , +.Xr ng_ether 4 , +.Xr ng_pppoe 4 , +.Xr vlan 4 , +.Xr ifconfig 8 Index: sys/conf/files =================================================================== --- sys/conf/files +++ sys/conf/files @@ -4060,6 +4060,7 @@ net/if_spppsubr.c optional sppp | netgraph_sppp net/if_stf.c optional stf inet inet6 net/if_tuntap.c optional tuntap +net/if_vether.c optional vether net/if_vlan.c optional vlan net/if_vxlan.c optional vxlan inet | vxlan inet6 net/ifdi_if.m optional ether pci iflib Index: sys/modules/Makefile =================================================================== --- sys/modules/Makefile +++ sys/modules/Makefile @@ -157,6 +157,7 @@ ${_if_ndis} \ ${_if_stf} \ if_tuntap \ + if_vether \ if_vlan \ if_vxlan \ iflib \ Index: sys/modules/if_vether/Makefile =================================================================== --- /dev/null +++ sys/modules/if_vether/Makefile @@ -0,0 +1,7 @@ +# $FreeBSD$ + +.PATH: ${SRCTOP}/sys/net +KMOD= if_vether +SRCS= if_vether.c + +.include Index: sys/net/if_vether.c =================================================================== --- /dev/null +++ sys/net/if_vether.c @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2009 Theo de Raadt + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Copyright (c) 2018 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 ``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 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Virtual Ethernet interface, ported from OpenBSD. This interface + * operates in conjunction with if_bridge(4). + */ + +#define vether_sdl(ifa) ((const struct sockaddr_dl *)(ifa)->ifa_addr) + +#define vether_lla(ifa) (vether_sdl(ifa)->sdl_data + vether_sdl(ifa)->sdl_nlen) + +#define vether_lla_equal(ifa, lla) ( \ + (vether_sdl(ifa)->sdl_type == IFT_ETHER) && \ + (vether_sdl(ifa)->sdl_alen == ETHER_ADDR_LEN) && \ + (bcmp(vether_lla(ifa), lla, ETHER_ADDR_LEN) == 0)) + +struct vether_softc { + struct ifmedia sc_ifm; /* fake media information */ + struct ifnet *sc_ifp; /* network interface. */ +}; +#define VETHER_IF_FLAGS (IFF_SIMPLEX|IFF_BROADCAST|IFF_MULTICAST) +#define VETHER_IFCAP_FLAGS (IFCAP_VLAN_MTU|IFCAP_JUMBO_MTU) +#define VETHER_IFM_FLAGS (IFM_ETHER|IFM_AUTO) + +static void vether_init(void *); +static void vether_stop(struct ifnet *, int); +static void vether_start(struct ifnet *); + +static int vether_media_change(struct ifnet *); +static void vether_media_status(struct ifnet *, struct ifmediareq *); +static int vether_ioctl(struct ifnet *, u_long, caddr_t); + +static int vether_clone_create(struct if_clone *, int, caddr_t); +static void vether_clone_destroy(struct ifnet *); + +VNET_DEFINE(struct if_clone *, vether_cloner); +#define V_vether_cloner VNET(vether_cloner) + +static const char vether_name[] = "vether"; + +static void +vnet_vether_init(const void *unused __unused) +{ + + V_vether_cloner = if_clone_simple(vether_name, + vether_clone_create, vether_clone_destroy, 0); +} +VNET_SYSINIT(vnet_vether_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, + vnet_vether_init, NULL); + +static void +vnet_vether_uninit(const void *unused __unused) +{ + + if_clone_detach(V_vether_cloner); +} +VNET_SYSUNINIT(vnet_vether_uninit, SI_SUB_PSEUDO, SI_ORDER_ANY, + vnet_vether_uninit, NULL); + +static int +vether_mod_event(module_t mod, int event, void *data) +{ + int error; + + switch (event) { + case MOD_LOAD: + case MOD_UNLOAD: + error = 0; + break; + default: + error = EOPNOTSUPP; + } + + return (error); +} + +static moduledata_t vether_mod = { + "if_vether", + vether_mod_event, + 0 +}; +DECLARE_MODULE(if_vether, vether_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); + +static int +vether_clone_create(struct if_clone *ifc, int unit, caddr_t data) +{ + struct vether_softc *sc; + struct ifnet *ifp; + struct ether_addr eaddr; + + /* Allocate software context. */ + sc = malloc(sizeof(struct vether_softc), M_DEVBUF, + M_WAITOK|M_ZERO); /* can't fail */ + ifp = sc->sc_ifp = if_alloc(IFT_ETHER); + if (ifp == NULL) { + free(sc, M_DEVBUF); + return (ENOSPC); + } + if_initname(ifp, vether_name, unit); + + ifp->if_softc = sc; + ifp->if_init = vether_init; + ifp->if_ioctl = vether_ioctl; + ifp->if_start = vether_start; + + ifp->if_flags = VETHER_IF_FLAGS; + + ifp->if_capabilities = VETHER_IFCAP_FLAGS; + ifp->if_capenable = VETHER_IFCAP_FLAGS; + + ifmedia_init(&sc->sc_ifm, 0, vether_media_change, + vether_media_status); + ifmedia_add(&sc->sc_ifm, VETHER_IFM_FLAGS, 0, NULL); + ifmedia_set(&sc->sc_ifm, VETHER_IFM_FLAGS); + + ether_gen_addr(ifp, &eaddr); + ether_ifattach(ifp, eaddr.octet); + + ifp->if_baudrate = 0; + + return (0); +} + +static void +vether_clone_destroy(struct ifnet *ifp) +{ + struct vether_softc *sc; + + vether_stop(ifp, 1); + + ifp->if_flags &= ~IFF_UP; + + ether_ifdetach(ifp); + + if_free(ifp); + + sc = ifp->if_softc; + free(sc, M_DEVBUF); +} + +static int +vether_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) +{ + struct vether_softc *sc; + struct ifreq *ifr; + int error; + + sc = ifp->if_softc; + ifr = (struct ifreq *)data; + error = 0; + switch (cmd) { + case SIOCSIFMTU: + if (ifr->ifr_mtu > ETHER_MAX_LEN_JUMBO) + error = EINVAL; + else + ifp->if_mtu = ifr->ifr_mtu; + break; + case SIOCSIFMEDIA: /* Media types can't be changed. */ + 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; + } + return (error); +} +static int +vether_media_change(struct ifnet *ifp) +{ + + return (0); +} + +static void +vether_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) +{ + + ifmr->ifm_active = IFM_ETHER | IFM_AUTO; + ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE; +} + +static void +vether_init(void *xsc) +{ + struct vether_softc *sc; + struct ifnet *ifp; + + sc = (struct vether_softc *)xsc; + ifp = sc->sc_ifp; + + ifp->if_drv_flags |= IFF_DRV_RUNNING; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; +} + +static void +vether_stop(struct ifnet *ifp, int disable) +{ + + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); +} + +/* + * I/O. + */ + +static void +vether_start(struct ifnet *ifp) +{ + struct mbuf *m; + int error; + + if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != + IFF_DRV_RUNNING) + return; + + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + for (;;) { + IFQ_DEQUEUE(&ifp->if_snd, m); + if (m == NULL) + break; + + BPF_MTAP(ifp, m); + + /* do some statistics */ + + if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len); + if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); + + /* discard, if not member of if_bridge(4) */ + if (ifp->if_bridge == NULL) + m->m_pkthdr.rcvif = ifp; + + /* + * Three cases are considered here: + * + * (a) Frame was tx'd by layer above. + * + * (b) Frame was rx'd by link-layer. + * + * (c) Data sink. + */ + if (m->m_pkthdr.rcvif == NULL) { + /* broadcast frame by if_bridge(4) */ + + m->m_pkthdr.rcvif = ifp; + + BRIDGE_OUTPUT(ifp, m, error); + if (error != 0) + m_freem(m); + } else if (m->m_pkthdr.rcvif != ifp) { + /* demultiplex any other frame */ + + m->m_pkthdr.rcvif = ifp; + + + (*ifp->if_input)(ifp, m); + } else + m_freem(m); + } + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; +}