-.\" $OpenBSD: ifconfig.8,v 1.259 2015/10/24 08:42:57 jmc Exp $
+.\" $OpenBSD: ifconfig.8,v 1.260 2015/10/24 10:52:05 reyk Exp $
.\" $NetBSD: ifconfig.8,v 1.11 1996/01/04 21:27:29 pk Exp $
.\" $FreeBSD: ifconfig.8,v 1.16 1998/02/01 07:03:29 steve Exp $
.\"
is an IPv4 address that will be used to find the nexthop in the MPLS
network.
.El
+.\" PAIR
+.Sh PAIR
+.nr nS 1
+.Bk -words
+.Nm ifconfig
+.Ar pair-interface
+.Op Oo Fl Oc Ns Cm patch Ar interface
+.Ek
+.nr nS 0
+.Pp
+The following options are available for a
+.Xr pair 4
+interface:
+.Bl -tag -width Ds
+.It Cm patch Ar interface
+Connect the interface with a second
+.Xr pair 4
+interface.
+Any outgoing packets from the first
+.Ar pair-interface
+will be received by the second
+.Ar interface
+and vice versa.
+This link allows to interconnect two routing domains locally.
+.It Fl patch
+If configured, disconnect the interface pair.
+.El
.\" PFLOW
.Sh PFLOW
.nr nS 1
-/* $OpenBSD: ifconfig.c,v 1.303 2015/10/23 01:19:04 dlg Exp $ */
+/* $OpenBSD: ifconfig.c,v 1.304 2015/10/24 10:52:05 reyk Exp $ */
/* $NetBSD: ifconfig.c,v 1.40 1997/10/01 02:19:43 enami Exp $ */
/*
void setifdesc(const char *, int);
void unsetifdesc(const char *, int);
void printifhwfeatures(const char *, int);
+void setpair(const char *, int);
+void unsetpair(const char *, int);
#else
void setignore(const char *, int);
#endif
{ "-descr", 1, 0, unsetifdesc },
{ "wol", IFXF_WOL, 0, setifxflags },
{ "-wol", -IFXF_WOL, 0, setifxflags },
+ { "patch", NEXTARG, 0, setpair },
+ { "-patch", 1, 0, unsetpair },
#else /* SMALL */
{ "powersave", NEXTARG0, 0, setignore },
{ "priority", NEXTARG, 0, setignore },
struct ifreq ifrdesc;
struct ifkalivereq ikardesc;
char ifdescr[IFDESCRSIZE];
+ char ifname[IF_NAMESIZE];
#endif
uint64_t *media_list;
int i;
(ikardesc.ikar_timeo != 0 || ikardesc.ikar_cnt != 0))
printf("\tkeepalive: timeout %d count %d\n",
ikardesc.ikar_timeo, ikardesc.ikar_cnt);
+ if (ioctl(s, SIOCGIFPAIR, &ifrdesc) == 0 && ifrdesc.ifr_index != 0 &&
+ if_indextoname(ifrdesc.ifr_index, ifname) != NULL)
+ printf("\tpatch: %s\n", ifname);
#endif
vlan_status();
#ifndef SMALL
}
#endif
+#ifndef SMALL
+void
+setpair(const char *val, int d)
+{
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ if ((ifr.ifr_index = if_nametoindex(val)) == 0) {
+ errno = ENOENT;
+ err(1, "patch %s", val);
+ }
+ if (ioctl(s, SIOCSIFPAIR, (caddr_t)&ifr) < 0)
+ warn("SIOCSIFPAIR");
+}
+
+void
+unsetpair(const char *val, int d)
+{
+ ifr.ifr_index = 0;
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ if (ioctl(s, SIOCSIFPAIR, (caddr_t)&ifr) < 0)
+ warn("SIOCSIFPAIR");
+}
+#endif
+
#ifdef SMALL
void
setignore(const char *id, int param)
-# $OpenBSD: Makefile,v 1.601 2015/10/23 16:44:25 claudio Exp $
+# $OpenBSD: Makefile,v 1.602 2015/10/24 10:52:05 reyk Exp $
MAN= aac.4 ac97.4 acphy.4 \
acpi.4 acpiac.4 acpiasus.4 acpibat.4 acpibtn.4 acpicpu.4 acpidock.4 \
nsclpcsio.4 nsgphy.4 nsphy.4 nsphyter.4 null.4 nviic.4 nvt.4 \
oce.4 ohci.4 options.4 onewire.4 oosiop.4 osiop.4 otus.4 \
owid.4 owctr.4 owsbm.4 \
- owtemp.4 pcagpio.4 pcaled.4 pcdisplay.4 pchb.4 pci.4 pcib.4 pcfadc.4 \
- pcfiic.4 pciide.4 pckbc.4 pckbd.4 pcmcia.4 pcn.4 pcppi.4 pcscp.4 \
- pf.4 pflog.4 pflow.4 pfsync.4 pgt.4 piixpm.4 pim.4 pipex.4 \
+ owtemp.4 pair.4 pcagpio.4 pcaled.4 pcdisplay.4 pchb.4 pci.4 pcib.4 \
+ pcfadc.4 pcfiic.4 pciide.4 pckbc.4 pckbd.4 pcmcia.4 pcn.4 pcppi.4 \
+ pcscp.4 pf.4 pflog.4 pflow.4 pfsync.4 pgt.4 piixpm.4 pim.4 pipex.4 \
pms.4 ppb.4 ppp.4 pppoe.4 pppx.4 pty.4 puc.4 pvbus.4 pwdog.4 \
qla.4 qle.4 qlw.4 qsphy.4 radio.4 \
ral.4 random.4 rdomain.4 rd.4 rdac.4 re.4 rdcphy.4 rgephy.4 ricohrtc.4 \
--- /dev/null
+.\" $OpenBSD: pair.4,v 1.1 2015/10/24 10:52:05 reyk Exp $
+.\"
+.\" Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
+.\" Copyright (c) 2009 Theo de Raadt <deraadt@openbsd.org>
+.\"
+.\" 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.
+.\"
+.Dd $Mdocdate: October 24 2015 $
+.Dt pair 4
+.Os
+.Sh NAME
+.Nm pair
+.Nd virtual Ethernet interface pair
+.Sh SYNOPSIS
+.Cd "pseudo-device pair"
+.Sh DESCRIPTION
+The
+.Nm
+interface simulates a normal Ethernet interface by encapsulating
+standard network frames with an Ethernet header, specifically for use
+in a pair of interfaces that are interconnected with each other.
+.Pp
+To use it, the administrator needs to create two
+.Nm
+interfaces and connect them;
+the interfaces are
+.Sq patched
+as it would be done with physical network ports.
+All packets that are sent on the first interface are received on the
+second interface.
+.Sh EXAMPLES
+Set up a pair of interfaces where each of them is a member of a different
+.Xr rdomain 4 :
+.Bd -literal -offset indent
+# ifconfig pair1 rdomain 1 10.1.1.1/24 up
+# ifconfig pair2 rdomain 2 10.1.1.2/24 up
+# ifconfig pair1 patch pair2
+# route -T 1 exec ping 10.1.1.2
+.Ed
+.Sh SEE ALSO
+.Xr bridge 4 ,
+.Xr inet 4 ,
+.Xr inet6 4 ,
+.Xr rdomain 4 ,
+.Xr hostname.if 5 ,
+.Xr ifconfig 8 ,
+.Xr netstart 8
+.Sh HISTORY
+The
+.Nm
+interface first appeared in
+.Ox 5.9 .
+.Sh AUTHORS
+The
+.Nm
+driver is based on
+.Xr vether 4
+by
+.An Theo de Raadt Aq Mt deraadt@openbsd.org .
+It has been extended and turned into
+.Xr pair 4
+by
+.An Reyk Floeter Aq Mt reyk@openbsd.org .
+.Sh BUGS
+Like
+.Xr tun 4 ,
+the Ethernet address chosen will be partially random, and may
+occasionally collide with another address.
-# $OpenBSD: GENERIC,v 1.221 2015/10/23 15:10:53 claudio Exp $
+# $OpenBSD: GENERIC,v 1.222 2015/10/24 10:52:05 reyk Exp $
#
# Machine-independent option; used by all architectures for their
# GENERIC kernel
pseudo-device loop # network loopback
pseudo-device mpe # MPLS PE interface
pseudo-device mpw # MPLS pseudowire support
+pseudo-device pair # Virtual Ethernet interface pair
pseudo-device ppp # PPP
pseudo-device pppoe # PPP over Ethernet (RFC 2516)
pseudo-device pppx # PPP multiplexer
-# $OpenBSD: files,v 1.604 2015/10/09 01:17:21 deraadt Exp $
+# $OpenBSD: files,v 1.605 2015/10/24 10:52:05 reyk Exp $
# $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
pseudo-device endrun: tty
pseudo-device loop: ifnet
+pseudo-device pair: ifnet, ether
pseudo-device ppp: ifnet
pseudo-device tun: ifnet
pseudo-device bpfilter: ifnet
file net/if_mpe.c mpe needs-count
file net/if_mpw.c mpw & bridge needs-count
file net/if_vether.c vether needs-count
+file net/if_pair.c pair needs-count
file net/if_pppx.c pppx needs-count
file net/if_vxlan.c vxlan needs-count
file net80211/ieee80211.c wlan
-/* $OpenBSD: if.c,v 1.393 2015/10/22 17:48:34 mpi Exp $ */
+/* $OpenBSD: if.c,v 1.394 2015/10/24 10:52:05 reyk Exp $ */
/* $NetBSD: if.c,v 1.35 1996/05/07 05:26:04 thorpej Exp $ */
/*
case SIOCDELMULTI:
case SIOCSIFMEDIA:
case SIOCSVNETID:
+ case SIOCSIFPAIR:
if ((error = suser(p, 0)) != 0)
return (error);
/* FALLTHROUGH */
case SIOCGLIFPHYTTL:
case SIOCGIFMEDIA:
case SIOCGVNETID:
+ case SIOCGIFPAIR:
if (ifp->if_ioctl == 0)
return (EOPNOTSUPP);
error = (*ifp->if_ioctl)(ifp, cmd, data);
-/* $OpenBSD: if.h,v 1.171 2015/10/23 10:22:29 claudio Exp $ */
+/* $OpenBSD: if.h,v 1.172 2015/10/24 10:52:05 reyk Exp $ */
/* $NetBSD: if.h,v 1.23 1996/05/07 02:40:27 thorpej Exp $ */
/*
uint32_t ifru_vnetid;
uint64_t ifru_media;
caddr_t ifru_data;
+ unsigned int ifru_index;
} ifr_ifru;
#define ifr_addr ifr_ifru.ifru_addr /* address */
#define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-to-p link */
#define ifr_vnetid ifr_ifru.ifru_vnetid /* Virtual Net Id */
#define ifr_ttl ifr_ifru.ifru_metric /* tunnel TTL (overload) */
#define ifr_data ifr_ifru.ifru_data /* for use by interface */
+#define ifr_index ifr_ifru.ifru_index /* interface index */
};
struct ifaliasreq {
--- /dev/null
+/* $OpenBSD: if_pair.c,v 1.1 2015/10/24 10:52:05 reyk Exp $ */
+
+/*
+ * Copyright (c) 2015 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2009 Theo de Raadt <deraadt@openbsd.org>
+ *
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include "bpfilter.h"
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+
+void pairattach(int);
+int pairioctl(struct ifnet *, u_long, caddr_t);
+void pairstart(struct ifnet *);
+int pair_clone_create(struct if_clone *, int);
+int pair_clone_destroy(struct ifnet *);
+int pair_media_change(struct ifnet *);
+void pair_media_status(struct ifnet *, struct ifmediareq *);
+void pair_link_state(struct ifnet *);
+
+struct pair_softc {
+ struct arpcom sc_ac;
+ struct ifmedia sc_media;
+ unsigned int sc_pairedif;
+};
+
+struct if_clone pair_cloner =
+ IF_CLONE_INITIALIZER("pair", pair_clone_create, pair_clone_destroy);
+
+int
+pair_media_change(struct ifnet *ifp)
+{
+ return (0);
+}
+
+void
+pair_media_status(struct ifnet *ifp, struct ifmediareq *imr)
+{
+ struct pair_softc *sc = ifp->if_softc;
+ struct ifnet *pairedifp;
+
+ imr->ifm_active = IFM_ETHER | IFM_AUTO;
+
+ if ((pairedifp = if_get(sc->sc_pairedif)) == NULL) {
+ imr->ifm_status = 0;
+ return;
+ }
+ if_put(pairedifp);
+
+ imr->ifm_status = IFM_AVALID | IFM_ACTIVE;
+}
+
+void
+pair_link_state(struct ifnet *ifp)
+{
+ struct pair_softc *sc = ifp->if_softc;
+ struct ifnet *pairedifp;
+ unsigned int link_state;
+
+ /* The pair state is determined by the paired interface */
+ if ((pairedifp = if_get(sc->sc_pairedif)) != NULL) {
+ link_state = LINK_STATE_UP;
+ if_put(pairedifp);
+ } else
+ link_state = LINK_STATE_DOWN;
+
+ if (ifp->if_link_state != link_state) {
+ ifp->if_link_state = link_state;
+ if_link_state_change(ifp);
+ }
+}
+
+void
+pairattach(int npair)
+{
+ if_clone_attach(&pair_cloner);
+}
+
+int
+pair_clone_create(struct if_clone *ifc, int unit)
+{
+ struct ifnet *ifp;
+ struct pair_softc *sc;
+
+ if ((sc = malloc(sizeof(*sc),
+ M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL)
+ return (ENOMEM);
+
+ ifp = &sc->sc_ac.ac_if;
+ snprintf(ifp->if_xname, sizeof ifp->if_xname, "pair%d", unit);
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ether_fakeaddr(ifp);
+
+ ifp->if_softc = sc;
+ ifp->if_ioctl = pairioctl;
+ ifp->if_start = pairstart;
+ IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
+ IFQ_SET_READY(&ifp->if_snd);
+
+ ifp->if_hardmtu = 0xffff;
+ ifp->if_capabilities = IFCAP_VLAN_MTU;
+
+ ifmedia_init(&sc->sc_media, 0, pair_media_change,
+ pair_media_status);
+ ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL);
+ ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO);
+
+ if_attach(ifp);
+ ether_ifattach(ifp);
+
+ pair_link_state(ifp);
+
+ return (0);
+}
+
+int
+pair_clone_destroy(struct ifnet *ifp)
+{
+ struct pair_softc *sc = ifp->if_softc;
+ struct ifnet *pairedifp;
+ struct pair_softc *dstsc = ifp->if_softc;
+
+ if ((pairedifp = if_get(sc->sc_pairedif)) != NULL) {
+ dstsc = pairedifp->if_softc;
+ dstsc->sc_pairedif = 0;
+ pair_link_state(pairedifp);
+ if_put(pairedifp);
+ }
+
+ ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY);
+ ether_ifdetach(ifp);
+ if_detach(ifp);
+ free(sc, M_DEVBUF, sizeof(*sc));
+
+ return (0);
+}
+
+void
+pairstart(struct ifnet *ifp)
+{
+ struct pair_softc *sc = (struct pair_softc *)ifp->if_softc;
+ struct mbuf_list ml = MBUF_LIST_INITIALIZER();
+ struct ifnet *pairedifp;
+ struct mbuf *m;
+
+ pairedifp = if_get(sc->sc_pairedif);
+
+ for (;;) {
+ IFQ_DEQUEUE(&ifp->if_snd, m);
+ if (m == NULL)
+ break;
+
+#if NBPFILTER > 0
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
+#endif /* NBPFILTER > 0 */
+
+ ifp->if_opackets++;
+ if (pairedifp != NULL)
+ ml_enqueue(&ml, m);
+ else
+ m_freem(m);
+ }
+
+ if (pairedifp != NULL) {
+ if_input(pairedifp, &ml);
+ if_put(pairedifp);
+ }
+}
+
+/* ARGSUSED */
+int
+pairioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+ struct pair_softc *sc = (struct pair_softc *)ifp->if_softc;
+ struct ifaddr *ifa = (struct ifaddr *)data;
+ struct ifreq *ifr = (struct ifreq *)data;
+ struct if_clone *ifc;
+ struct pair_softc *pairedsc = ifp->if_softc;
+ struct ifnet *oldifp = NULL, *newifp = NULL;
+ int error = 0, unit;
+
+ switch (cmd) {
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+ if (ifa->ifa_addr->sa_family == AF_INET)
+ arp_ifinit(&sc->sc_ac, ifa);
+ /* FALLTHROUGH */
+
+ case SIOCSIFFLAGS:
+ if (ifp->if_flags & IFF_UP)
+ ifp->if_flags |= IFF_RUNNING;
+ else
+ ifp->if_flags &= ~IFF_RUNNING;
+ break;
+
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ break;
+
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
+ break;
+
+ case SIOCSIFPAIR:
+ if (sc->sc_pairedif == ifr->ifr_index)
+ break;
+
+ /* Cannot link to myself */
+ if (ifr->ifr_index == ifp->if_index) {
+ error = EINVAL;
+ break;
+ }
+
+ oldifp = if_get(sc->sc_pairedif);
+ newifp = if_get(ifr->ifr_index);
+
+ if (newifp != NULL) {
+ pairedsc = newifp->if_softc;
+
+ if (pairedsc->sc_pairedif != 0) {
+ error = EBUSY;
+ break;
+ }
+
+ /* Only allow pair(4) interfaces for the pair */
+ if ((ifc = if_clone_lookup(newifp->if_xname,
+ &unit)) == NULL || strcmp("pair",
+ ifc->ifc_name) != 0) {
+ error = ENODEV;
+ break;
+ }
+
+ pairedsc = newifp->if_softc;
+ pairedsc->sc_pairedif = ifp->if_index;
+ sc->sc_pairedif = ifr->ifr_index;
+ } else
+ sc->sc_pairedif = 0;
+
+ if (oldifp != NULL) {
+ pairedsc = oldifp->if_softc;
+ pairedsc->sc_pairedif = 0;
+ }
+ break;
+
+ case SIOCGIFPAIR:
+ ifr->ifr_index = sc->sc_pairedif;
+ break;
+
+ default:
+ error = ether_ioctl(ifp, &sc->sc_ac, cmd, data);
+ }
+
+ if (newifp != NULL || oldifp != NULL)
+ pair_link_state(ifp);
+ if (oldifp != NULL) {
+ pair_link_state(oldifp);
+ if_put(oldifp);
+ }
+ if (newifp != NULL) {
+ pair_link_state(newifp);
+ if_put(newifp);
+ }
+
+ return (error);
+}
-/* $OpenBSD: if_var.h,v 1.49 2015/10/22 17:48:34 mpi Exp $ */
+/* $OpenBSD: if_var.h,v 1.50 2015/10/24 10:52:05 reyk Exp $ */
/* $NetBSD: if.h,v 1.23 1996/05/07 02:40:27 thorpej Exp $ */
/*
int if_clone_create(const char *);
int if_clone_destroy(const char *);
+struct if_clone *
+ if_clone_lookup(const char *, int *);
+
int sysctl_mq(int *, u_int, void *, size_t *, void *, size_t,
struct mbuf_queue *);
-/* $OpenBSD: sockio.h,v 1.61 2015/10/23 01:19:04 dlg Exp $ */
+/* $OpenBSD: sockio.h,v 1.62 2015/10/24 10:52:05 reyk Exp $ */
/* $NetBSD: sockio.h,v 1.5 1995/08/23 00:40:47 thorpej Exp $ */
/*-
#define SIOCDVNETID _IOW('i', 175, struct ifreq) /* del virt net id */
+#define SIOCSIFPAIR _IOW('i', 176, struct ifreq) /* set paired if */
+#define SIOCGIFPAIR _IOWR('i', 177, struct ifreq) /* get paired if */
+
#define SIOCSVH _IOWR('i', 245, struct ifreq) /* set carp param */
#define SIOCGVH _IOWR('i', 246, struct ifreq) /* get carp param */