hi,
the following diff allows to create a "virtual crossover" link between
two vether(4) interfaces that helps to connect two rdomains locally.
it is like a crossover cable between two virtual devices - you can
connect a vether(4) (a) with another vether(4) (b) interface that will
receive the outgoing packets of (a) via ether_input() and vice versa.
configuration example (also see manpage bits below):
# ifconfig vether0 192.168.1.1
# ifconfig vether1 rdomain 1 192.168.1.2
# ifconfig vether0 xdev vether1
you can skip the following step because the devices are already
connected in both directions:
# ifconfig vether1 xdev vether0
and now you can ping vether1 in rdomain 1 from vether0 in rdomain 0:
# ping 192.168.1.2
...and vice versa
# route -T 1 exec ping 192.168.1.1
the following is also possible because we have a true "ethernet" link:
# dhcpd vether0
# dhclient vether1
this diff is for after unlock but I'd like to get some feedback and
testing. go ping yourself.
reyk
Index: sys/net/if.c
===================================================================
RCS file: /cvs/src/sys/net/if.c,v
retrieving revision 1.233
diff -u -p -r1.233 if.c
--- sys/net/if.c 25 Jan 2011 05:44:05 -0000 1.233
+++ sys/net/if.c 28 Jan 2011 12:17:38 -0000
@@ -67,6 +67,7 @@
#include "carp.h"
#include "pf.h"
#include "trunk.h"
+#include "vether.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -149,7 +150,6 @@ int if_getgroupattribs(caddr_t);
int if_setgroupattribs(caddr_t);
int if_clone_list(struct if_clonereq *);
-struct if_clone *if_clone_lookup(const char *, int *);
void if_congestion_clear(void *);
int if_group_egress_build(void);
@@ -524,6 +524,11 @@ if_detach(struct ifnet *ifp)
/* Call detach hooks, ie. to remove vlan interfaces */
dohooks(ifp->if_detachhooks, HOOK_REMOVE | HOOK_FREE);
+#if NVETHER > 0
+ /* Unlink any crossover link */
+ (void)if_crossover(ifp, NULL);
+#endif
+
#if NTRUNK > 0
if (ifp->if_type == IFT_IEEE8023ADLAG)
trunk_port_ifdetach(ifp);
@@ -2340,3 +2345,35 @@ ifnewlladdr(struct ifnet *ifp)
}
splx(s);
}
+
+#if NVETHER > 0
+/*
+ * Create or delete a virtual crossover link
+ */
+int
+if_crossover(struct ifnet *ifp, struct ifnet *xif)
+{
+ struct ifnet *oldxif = ifp->if_xif;
+ int s;
+
+ if (ifp == xif)
+ return (EINVAL);
+
+ s = splnet();
+
+ /* First unlink any connected interfaces */
+ if (oldxif)
+ oldxif->if_xif = NULL;
+ if (xif)
+ (void)if_crossover(xif, NULL);
+
+ /* Establish new crossover link between two interfaces */
+ ifp->if_xif = xif;
+ if (xif)
+ xif->if_xif = ifp;
+
+ splx(s);
+
+ return (0);
+}
+#endif
Index: sys/net/if.h
===================================================================
RCS file: /cvs/src/sys/net/if.h,v
retrieving revision 1.121
diff -u -p -r1.121 if.h
--- sys/net/if.h 17 Nov 2010 18:51:57 -0000 1.121
+++ sys/net/if.h 28 Jan 2011 12:17:39 -0000
@@ -244,6 +244,7 @@ struct ifnet { /* and the
entries */
caddr_t if_bridge; /* bridge structure */
caddr_t if_tp; /* used by trunk ports */
caddr_t if_pf_kif; /* pf interface abstraction */
+ struct ifnet *if_xif; /* crossover interface */
union {
caddr_t carp_s; /* carp structure (used by !carp ifs) */
struct ifnet *carp_d; /* ptr to carpdev (used by carp ifs) */
@@ -820,6 +821,7 @@ void if_group_routechange(struct sockadd
struct ifnet *ifunit(const char *);
void if_start(struct ifnet *);
void ifnewlladdr(struct ifnet *);
+int if_crossover(struct ifnet *, struct ifnet *);
struct ifaddr *ifa_ifwithaddr(struct sockaddr *, u_int);
struct ifaddr *ifa_ifwithaf(int, u_int);
@@ -836,6 +838,7 @@ void if_clone_detach(struct if_clone *);
int if_clone_create(const char *);
int if_clone_destroy(const char *);
+struct if_clone *if_clone_lookup(const char *, int *);
void if_congestion(struct ifqueue *);
int sysctl_ifq(int *, u_int, void *, size_t *, void *, size_t,
Index: sys/net/if_vether.c
===================================================================
RCS file: /cvs/src/sys/net/if_vether.c,v
retrieving revision 1.15
diff -u -p -r1.15 if_vether.c
--- sys/net/if_vether.c 2 Apr 2010 21:45:49 -0000 1.15
+++ sys/net/if_vether.c 28 Jan 2011 12:17:39 -0000
@@ -24,6 +24,11 @@
#include <sys/sockio.h>
#include <sys/ioctl.h>
+#include "bpfilter.h"
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_media.h>
@@ -114,7 +119,8 @@ vether_clone_destroy(struct ifnet *ifp)
/*
* The bridge has magically already done all the work for us,
- * and we only need to discard the packets.
+ * and we only need to discard the packets or forward them
+ * to a crosslinked device.
*/
void
vetherstart(struct ifnet *ifp)
@@ -130,7 +136,28 @@ vetherstart(struct ifnet *ifp)
if (m == NULL)
return;
ifp->if_opackets++;
- m_freem(m);
+
+#if NBPFILTER > 0
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
+#endif
+
+ if (ifp->if_xif == NULL)
+ m_freem(m);
+ else {
+ /* Forward the packet to another crosslinked device */
+ m->m_pkthdr.rcvif = ifp->if_xif;
+
+#if NBPFILTER > 0
+ if (ifp->if_xif->if_bpf)
+ bpf_mtap(ifp->if_xif->if_bpf, m,
+ BPF_DIRECTION_IN);
+#endif
+
+ ifp->if_xif->if_ipackets++;
+ ether_input(ifp->if_xif, NULL, m);
+
+ }
}
}
@@ -143,9 +170,49 @@ vetherioctl(struct ifnet *ifp, u_long cm
struct ifaddr *ifa = (struct ifaddr *)data;
#endif
struct ifreq *ifr = (struct ifreq *)data;
- int error = 0, link_state;
+ struct ifnet *xif;
+ struct if_clone *ifc;
+ int error = 0, link_state, unit;
+ char xifname[IFNAMSIZ];
switch (cmd) {
+ case SIOCSETXDEV:
+ if ((error = suser(curproc, 0)) != 0)
+ break;
+ if ((error = copyin(ifr->ifr_data, &xifname, sizeof(xifname))))
+ break;
+ if (xifname[0] == '\0') {
+ if_crossover(ifp, NULL);
+ break;
+ }
+
+ /*
+ * Only allow vether(4) interfaces for the crossover.
+ * It would also work to send packets to other interfaces but
+ * they would not support bidirectional communication.
+ */
+ if ((ifc = if_clone_lookup(xifname, &unit)) == NULL ||
+ strcmp("vether", ifc->ifc_name) != 0) {
+ error = ENODEV;
+ break;
+ }
+
+ (void)if_clone_create(xifname);
+ if ((xif = ifunit(xifname)) == NULL) {
+ error = ENOENT;
+ break;
+ }
+ error = if_crossover(ifp, xif);
+ break;
+
+ case SIOCGETXDEV:
+ bzero(&xifname, sizeof(xifname));
+ if (ifp->if_xif)
+ snprintf(xifname, sizeof(xifname),
+ "%s", ifp->if_xif->if_xname);
+ error = copyout(&xifname, ifr->ifr_data, sizeof(xifname));
+ break;
+
case SIOCSIFADDR:
ifp->if_flags |= IFF_UP;
#ifdef INET
Index: sys/sys/sockio.h
===================================================================
RCS file: /cvs/src/sys/sys/sockio.h,v
retrieving revision 1.48
diff -u -p -r1.48 sockio.h
--- sys/sys/sockio.h 3 Jul 2010 04:44:51 -0000 1.48
+++ sys/sys/sockio.h 28 Jan 2011 12:17:39 -0000
@@ -182,6 +182,9 @@
#define SIOCSETKALIVE _IOW('i', 163, struct ifkalivereq)
#define SIOCGETKALIVE _IOWR('i', 164, struct ifkalivereq)
+#define SIOCSETXDEV _IOW('i', 165, struct ifreq) /* set xover device */
+#define SIOCGETXDEV _IOWR('i', 166, struct ifreq) /* get xover device */
+
#define SIOCSVH _IOWR('i', 245, struct ifreq) /* set carp
param */
#define SIOCGVH _IOWR('i', 246, struct ifreq) /* get carp
param */
Index: sbin/ifconfig/ifconfig.8
===================================================================
RCS file: /cvs/src/sbin/ifconfig/ifconfig.8,v
retrieving revision 1.212
diff -u -p -r1.212 ifconfig.8
--- sbin/ifconfig/ifconfig.8 23 Dec 2010 08:54:59 -0000 1.212
+++ sbin/ifconfig/ifconfig.8 28 Jan 2011 12:17:40 -0000
@@ -1451,6 +1451,36 @@ interface itself.
can be set to any valid routing table ID;
the corresponding routing domain is derived from this table.
.El
+.\" VETHER
+.Sh VETHER
+.nr nS 1
+.Bk -words
+.Nm ifconfig
+.Ar vether-interface
+.Op Oo Fl Oc Ns Cm xdev Ar crossover-interface
+.Ek
+.nr nS 0
+.Pp
+The following options are available for a
+.Xr vether 4
+interface:
+.Bl -tag -width Ds
+.It Cm xdev Ar crossover-interface
+Create a virtual crossover link with another
+.Xr vether 4
+interface.
+Any outgoing packets from the
+.Ar vether-interface
+will be received by the
+.Ar crossover-interface
+and vice versa.
+This link allows to interconnect two routing domains locally,
+see the
+.Xr vether 4
+manual page for more information.
+.It Fl xdev
+If configured, disconnect the virtual crossover link.
+.El
.\" VLAN
.Sh VLAN
.nr nS 1
Index: sbin/ifconfig/ifconfig.c
===================================================================
RCS file: /cvs/src/sbin/ifconfig/ifconfig.c,v
retrieving revision 1.242
diff -u -p -r1.242 ifconfig.c
--- sbin/ifconfig/ifconfig.c 9 Nov 2010 21:14:47 -0000 1.242
+++ sbin/ifconfig/ifconfig.c 28 Jan 2011 12:17:41 -0000
@@ -199,8 +199,10 @@ void setvlantag(const char *, int);
void setvlanprio(const char *, int);
void setvlandev(const char *, int);
void unsetvlandev(const char *, int);
+void setxdev(const char *, int);
void mpe_status(void);
void vlan_status(void);
+void x_status(void);
void getifgroups(void);
void carp_status(void);
void setcarp_advbase(const char *,int);
@@ -348,6 +350,8 @@ const struct cmd {
{ "-autoconfprivacy", -IFXF_INET6_PRIVACY, 0, setifxflags },
#endif /*INET6*/
#ifndef SMALL
+ { "xdev", NEXTARG, 0, setxdev },
+ { "-xdev", -1, 0, setxdev },
{ "rtlabel", NEXTARG, 0, setifrtlabel },
{ "-rtlabel", -1, 0, setifrtlabel },
{ "range", NEXTARG, 0, setatrange },
@@ -2791,6 +2795,7 @@ status(int link, struct sockaddr_dl *sdl
trunk_status();
mpe_status();
pflow_status();
+ x_status();
#endif
getifgroups();
@@ -3442,6 +3447,36 @@ unsetvlandev(const char *val, int d)
}
#ifndef SMALL
+/* ARGSUSED */
+void
+setxdev(const char *val, int d)
+{
+ char xifname[IFNAMSIZ];
+
+ bzero(&xifname, sizeof(xifname));
+ if (d != -1)
+ (void)strlcpy(xifname, val, sizeof(xifname));
+ ifr.ifr_data = (caddr_t)&xifname;
+
+ if (ioctl(s, SIOCSETXDEV, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSETXDEV");
+}
+
+void
+x_status(void)
+{
+ char xifname[IFNAMSIZ];
+
+ bzero(&xifname, sizeof(xifname));
+ ifr.ifr_data = (caddr_t)&xifname;
+
+ if (ioctl(s, SIOCGETXDEV, (caddr_t)&ifr) == -1)
+ return;
+
+ if (xifname[0] != 0)
+ printf("\txdev: %s\n", xifname);
+}
+
static const char *carp_states[] = { CARP_STATES };
static const char *carp_bal_modes[] = { CARP_BAL_MODES };
Index: share/man/man4/vether.4
===================================================================
RCS file: /cvs/src/share/man/man4/vether.4,v
retrieving revision 1.3
diff -u -p -r1.3 vether.4
--- share/man/man4/vether.4 22 Nov 2009 14:44:26 -0000 1.3
+++ share/man/man4/vether.4 28 Jan 2011 12:17:41 -0000
@@ -39,6 +39,23 @@ An Ethernet header will be prepended and
interface is a member of a
.Xr bridge ,
the frame will show up there.
+.Sh VIRTUAL CROSSOVER
+.Nm
+can also be configured to create a virtual crossover link with another
+.Nm
+interface.
+Any outgoing packets that will be sent from the
+.Nm
+interface will be received by the configured crossover interface and
+vice versa.
+.Pp
+This can be used to interconnect two routing domains locally.
+For example:
+.Bd -literal -offset indent
+# ifconfig vether0 192.168.1.1
+# ifconfig vether1 rdomain 1 192.168.1.2
+# ifconfig vether0 xdev vether1
+.Ed
.Sh SEE ALSO
.Xr bridge 4 ,
.Xr inet 4 ,