Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4ff4d8d3 authored by Nolan Leake's avatar Nolan Leake Committed by Linus Torvalds
Browse files

um: add ucast ethernet transport



The ucast transport is similar to the mcast transport (and, in fact,
shares most of its code), only it uses UDP unicast to move packets.

Obviously this is only useful for point-to-point connections between
virtual ethernet devices.

Signed-off-by: default avatarNolan Leake <nolan@cumulusnetworks.com>
Signed-off-by: default avatarRichard Weinberger <richard@nod.at>
Cc: David Miller <davem@davemloft.net>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent d634f194
Loading
Loading
Loading
Loading
+10 −0
Original line number Original line Diff line number Diff line
@@ -1182,6 +1182,16 @@
  forge.net/>  and explains these in detail, as well as
  forge.net/>  and explains these in detail, as well as
  some other issues.
  some other issues.


  There is also a related point-to-point only "ucast" transport.
  This is useful when your network does not support multicast, and
  all network connections are simple point to point links.

  The full set of command line options for this transport are


       ethn=ucast,ethernet address,remote address,listen port,remote port






  66..66..  TTUUNN//TTAAPP wwiitthh tthhee uummll__nneett hheellppeerr
  66..66..  TTUUNN//TTAAPP wwiitthh tthhee uummll__nneett hheellppeerr
+2 −2
Original line number Original line Diff line number Diff line
@@ -9,7 +9,7 @@
slip-objs := slip_kern.o slip_user.o
slip-objs := slip_kern.o slip_user.o
slirp-objs := slirp_kern.o slirp_user.o
slirp-objs := slirp_kern.o slirp_user.o
daemon-objs := daemon_kern.o daemon_user.o
daemon-objs := daemon_kern.o daemon_user.o
mcast-objs := mcast_kern.o mcast_user.o
umcast-objs := umcast_kern.o umcast_user.o
net-objs := net_kern.o net_user.o
net-objs := net_kern.o net_user.o
mconsole-objs := mconsole_kern.o mconsole_user.o
mconsole-objs := mconsole_kern.o mconsole_user.o
hostaudio-objs := hostaudio_kern.o
hostaudio-objs := hostaudio_kern.o
@@ -44,7 +44,7 @@ obj-$(CONFIG_UML_NET_SLIP) += slip.o slip_common.o
obj-$(CONFIG_UML_NET_SLIRP) += slirp.o slip_common.o
obj-$(CONFIG_UML_NET_SLIRP) += slirp.o slip_common.o
obj-$(CONFIG_UML_NET_DAEMON) += daemon.o 
obj-$(CONFIG_UML_NET_DAEMON) += daemon.o 
obj-$(CONFIG_UML_NET_VDE) += vde.o
obj-$(CONFIG_UML_NET_VDE) += vde.o
obj-$(CONFIG_UML_NET_MCAST) += mcast.o 
obj-$(CONFIG_UML_NET_MCAST) += umcast.o
obj-$(CONFIG_UML_NET_PCAP) += pcap.o
obj-$(CONFIG_UML_NET_PCAP) += pcap.o
obj-$(CONFIG_UML_NET) += net.o 
obj-$(CONFIG_UML_NET) += net.o 
obj-$(CONFIG_MCONSOLE) += mconsole.o
obj-$(CONFIG_MCONSOLE) += mconsole.o
+27 −0
Original line number Original line Diff line number Diff line
@@ -3,22 +3,25 @@
 * Licensed under the GPL
 * Licensed under the GPL
 */
 */


#ifndef __DRIVERS_MCAST_H
#ifndef __DRIVERS_UMCAST_H
#define __DRIVERS_MCAST_H
#define __DRIVERS_UMCAST_H


#include "net_user.h"
#include "net_user.h"


struct mcast_data {
struct umcast_data {
	char *addr;
	char *addr;
	unsigned short port;
	unsigned short lport;
	void *mcast_addr;
	unsigned short rport;
	void *listen_addr;
	void *remote_addr;
	int ttl;
	int ttl;
	int unicast;
	void *dev;
	void *dev;
};
};


extern const struct net_user_info mcast_user_info;
extern const struct net_user_info umcast_user_info;


extern int mcast_user_write(int fd, void *buf, int len, 
extern int umcast_user_write(int fd, void *buf, int len,
			    struct mcast_data *pri);
			     struct umcast_data *pri);


#endif
#endif
+188 −0
Original line number Original line Diff line number Diff line
@@ -13,60 +13,69 @@


#include "linux/init.h"
#include "linux/init.h"
#include <linux/netdevice.h>
#include <linux/netdevice.h>
#include "mcast.h"
#include "umcast.h"
#include "net_kern.h"
#include "net_kern.h"


struct mcast_init {
struct umcast_init {
	char *addr;
	char *addr;
	int port;
	int lport;
	int rport;
	int ttl;
	int ttl;
	bool unicast;
};
};


static void mcast_init(struct net_device *dev, void *data)
static void umcast_init(struct net_device *dev, void *data)
{
{
	struct uml_net_private *pri;
	struct uml_net_private *pri;
	struct mcast_data *dpri;
	struct umcast_data *dpri;
	struct mcast_init *init = data;
	struct umcast_init *init = data;


	pri = netdev_priv(dev);
	pri = netdev_priv(dev);
	dpri = (struct mcast_data *) pri->user;
	dpri = (struct umcast_data *) pri->user;
	dpri->addr = init->addr;
	dpri->addr = init->addr;
	dpri->port = init->port;
	dpri->lport = init->lport;
	dpri->rport = init->rport;
	dpri->unicast = init->unicast;
	dpri->ttl = init->ttl;
	dpri->ttl = init->ttl;
	dpri->dev = dev;
	dpri->dev = dev;


	printk("mcast backend multicast address: %s:%u, TTL:%u\n",
	if (dpri->unicast) {
	       dpri->addr, dpri->port, dpri->ttl);
		printk(KERN_INFO "ucast backend address: %s:%u listen port: "
		       "%u\n", dpri->addr, dpri->rport, dpri->lport);
	} else {
		printk(KERN_INFO "mcast backend multicast address: %s:%u, "
		       "TTL:%u\n", dpri->addr, dpri->lport, dpri->ttl);
	}
}
}


static int mcast_read(int fd, struct sk_buff *skb, struct uml_net_private *lp)
static int umcast_read(int fd, struct sk_buff *skb, struct uml_net_private *lp)
{
{
	return net_recvfrom(fd, skb_mac_header(skb),
	return net_recvfrom(fd, skb_mac_header(skb),
			    skb->dev->mtu + ETH_HEADER_OTHER);
			    skb->dev->mtu + ETH_HEADER_OTHER);
}
}


static int mcast_write(int fd, struct sk_buff *skb, struct uml_net_private *lp)
static int umcast_write(int fd, struct sk_buff *skb, struct uml_net_private *lp)
{
{
	return mcast_user_write(fd, skb->data, skb->len,
	return umcast_user_write(fd, skb->data, skb->len,
				(struct mcast_data *) &lp->user);
				(struct umcast_data *) &lp->user);
}
}


static const struct net_kern_info mcast_kern_info = {
static const struct net_kern_info umcast_kern_info = {
	.init			= mcast_init,
	.init			= umcast_init,
	.protocol		= eth_protocol,
	.protocol		= eth_protocol,
	.read			= mcast_read,
	.read			= umcast_read,
	.write			= mcast_write,
	.write			= umcast_write,
};
};


static int mcast_setup(char *str, char **mac_out, void *data)
static int mcast_setup(char *str, char **mac_out, void *data)
{
{
	struct mcast_init *init = data;
	struct umcast_init *init = data;
	char *port_str = NULL, *ttl_str = NULL, *remain;
	char *port_str = NULL, *ttl_str = NULL, *remain;
	char *last;
	char *last;


	*init = ((struct mcast_init)
	*init = ((struct umcast_init)
		{ .addr	= "239.192.168.1",
		{ .addr	= "239.192.168.1",
		  .port 	= 1102,
		  .lport	= 1102,
		  .ttl	= 1 });
		  .ttl	= 1 });


	remain = split_if_spec(str, mac_out, &init->addr, &port_str, &ttl_str,
	remain = split_if_spec(str, mac_out, &init->addr, &port_str, &ttl_str,
@@ -78,7 +87,7 @@ static int mcast_setup(char *str, char **mac_out, void *data)
	}
	}


	if (port_str != NULL) {
	if (port_str != NULL) {
		init->port = simple_strtoul(port_str, &last, 10);
		init->lport = simple_strtoul(port_str, &last, 10);
		if ((*last != '\0') || (last == port_str)) {
		if ((*last != '\0') || (last == port_str)) {
			printk(KERN_ERR "mcast_setup - Bad port : '%s'\n",
			printk(KERN_ERR "mcast_setup - Bad port : '%s'\n",
			       port_str);
			       port_str);
@@ -95,8 +104,56 @@ static int mcast_setup(char *str, char **mac_out, void *data)
		}
		}
	}
	}


	init->unicast = false;
	init->rport = init->lport;

	printk(KERN_INFO "Configured mcast device: %s:%u-%u\n", init->addr,
	printk(KERN_INFO "Configured mcast device: %s:%u-%u\n", init->addr,
	       init->port, init->ttl);
	       init->lport, init->ttl);

	return 1;
}

static int ucast_setup(char *str, char **mac_out, void *data)
{
	struct umcast_init *init = data;
	char *lport_str = NULL, *rport_str = NULL, *remain;
	char *last;

	*init = ((struct umcast_init)
		{ .addr		= "",
		  .lport	= 1102,
		  .rport	= 1102 });

	remain = split_if_spec(str, mac_out, &init->addr,
			       &lport_str, &rport_str, NULL);
	if (remain != NULL) {
		printk(KERN_ERR "ucast_setup - Extra garbage on "
		       "specification : '%s'\n", remain);
		return 0;
	}

	if (lport_str != NULL) {
		init->lport = simple_strtoul(lport_str, &last, 10);
		if ((*last != '\0') || (last == lport_str)) {
			printk(KERN_ERR "ucast_setup - Bad listen port : "
			       "'%s'\n", lport_str);
			return 0;
		}
	}

	if (rport_str != NULL) {
		init->rport = simple_strtoul(rport_str, &last, 10);
		if ((*last != '\0') || (last == rport_str)) {
			printk(KERN_ERR "ucast_setup - Bad remote port : "
			       "'%s'\n", rport_str);
			return 0;
		}
	}

	init->unicast = true;

	printk(KERN_INFO "Configured ucast device: :%u -> %s:%u\n",
	       init->lport, init->addr, init->rport);


	return 1;
	return 1;
}
}
@@ -105,16 +162,27 @@ static struct transport mcast_transport = {
	.list	= LIST_HEAD_INIT(mcast_transport.list),
	.list	= LIST_HEAD_INIT(mcast_transport.list),
	.name	= "mcast",
	.name	= "mcast",
	.setup	= mcast_setup,
	.setup	= mcast_setup,
	.user 		= &mcast_user_info,
	.user	= &umcast_user_info,
	.kern 		= &mcast_kern_info,
	.kern	= &umcast_kern_info,
	.private_size 	= sizeof(struct mcast_data),
	.private_size	= sizeof(struct umcast_data),
	.setup_size 	= sizeof(struct mcast_init),
	.setup_size	= sizeof(struct umcast_init),
};

static struct transport ucast_transport = {
	.list	= LIST_HEAD_INIT(ucast_transport.list),
	.name	= "ucast",
	.setup	= ucast_setup,
	.user	= &umcast_user_info,
	.kern	= &umcast_kern_info,
	.private_size	= sizeof(struct umcast_data),
	.setup_size	= sizeof(struct umcast_init),
};
};


static int register_mcast(void)
static int register_umcast(void)
{
{
	register_transport(&mcast_transport);
	register_transport(&mcast_transport);
	register_transport(&ucast_transport);
	return 0;
	return 0;
}
}


late_initcall(register_mcast);
late_initcall(register_umcast);
+186 −0
Original line number Original line Diff line number Diff line
@@ -16,7 +16,7 @@
#include <errno.h>
#include <errno.h>
#include <netinet/in.h>
#include <netinet/in.h>
#include "kern_constants.h"
#include "kern_constants.h"
#include "mcast.h"
#include "umcast.h"
#include "net_user.h"
#include "net_user.h"
#include "um_malloc.h"
#include "um_malloc.h"
#include "user.h"
#include "user.h"
@@ -32,94 +32,112 @@ static struct sockaddr_in *new_addr(char *addr, unsigned short port)
		return NULL;
		return NULL;
	}
	}
	sin->sin_family = AF_INET;
	sin->sin_family = AF_INET;
	if (addr)
		sin->sin_addr.s_addr = in_aton(addr);
		sin->sin_addr.s_addr = in_aton(addr);
	else
		sin->sin_addr.s_addr = INADDR_ANY;
	sin->sin_port = htons(port);
	sin->sin_port = htons(port);
	return sin;
	return sin;
}
}


static int mcast_user_init(void *data, void *dev)
static int umcast_user_init(void *data, void *dev)
{
{
	struct mcast_data *pri = data;
	struct umcast_data *pri = data;


	pri->mcast_addr = new_addr(pri->addr, pri->port);
	pri->remote_addr = new_addr(pri->addr, pri->rport);
	if (pri->unicast)
		pri->listen_addr = new_addr(NULL, pri->lport);
	else
		pri->listen_addr = pri->remote_addr;
	pri->dev = dev;
	pri->dev = dev;
	return 0;
	return 0;
}
}


static void mcast_remove(void *data)
static void umcast_remove(void *data)
{
{
	struct mcast_data *pri = data;
	struct umcast_data *pri = data;


	kfree(pri->mcast_addr);
	kfree(pri->listen_addr);
	pri->mcast_addr = NULL;
	if (pri->unicast)
		kfree(pri->remote_addr);
	pri->listen_addr = pri->remote_addr = NULL;
}
}


static int mcast_open(void *data)
static int umcast_open(void *data)
{
{
	struct mcast_data *pri = data;
	struct umcast_data *pri = data;
	struct sockaddr_in *sin = pri->mcast_addr;
	struct sockaddr_in *lsin = pri->listen_addr;
	struct sockaddr_in *rsin = pri->remote_addr;
	struct ip_mreq mreq;
	struct ip_mreq mreq;
	int fd, yes = 1, err = -EINVAL;
	int fd, yes = 1, err = -EINVAL;




	if ((sin->sin_addr.s_addr == 0) || (sin->sin_port == 0))
	if ((!pri->unicast && lsin->sin_addr.s_addr == 0) ||
	    (rsin->sin_addr.s_addr == 0) ||
	    (lsin->sin_port == 0) || (rsin->sin_port == 0))
		goto out;
		goto out;


	fd = socket(AF_INET, SOCK_DGRAM, 0);
	fd = socket(AF_INET, SOCK_DGRAM, 0);


	if (fd < 0) {
	if (fd < 0) {
		err = -errno;
		err = -errno;
		printk(UM_KERN_ERR "mcast_open : data socket failed, "
		printk(UM_KERN_ERR "umcast_open : data socket failed, "
		       "errno = %d\n", errno);
		       "errno = %d\n", errno);
		goto out;
		goto out;
	}
	}


	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
		err = -errno;
		err = -errno;
		printk(UM_KERN_ERR "mcast_open: SO_REUSEADDR failed, "
		printk(UM_KERN_ERR "umcast_open: SO_REUSEADDR failed, "
		       "errno = %d\n", errno);
		       "errno = %d\n", errno);
		goto out_close;
		goto out_close;
	}
	}


	if (!pri->unicast) {
		/* set ttl according to config */
		/* set ttl according to config */
		if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &pri->ttl,
		if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &pri->ttl,
			       sizeof(pri->ttl)) < 0) {
			       sizeof(pri->ttl)) < 0) {
			err = -errno;
			err = -errno;
		printk(UM_KERN_ERR "mcast_open: IP_MULTICAST_TTL failed, "
			printk(UM_KERN_ERR "umcast_open: IP_MULTICAST_TTL "
		       "error = %d\n", errno);
			       "failed, error = %d\n", errno);
			goto out_close;
			goto out_close;
		}
		}


		/* set LOOP, so data does get fed back to local sockets */
		/* set LOOP, so data does get fed back to local sockets */
	if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
		if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP,
			       &yes, sizeof(yes)) < 0) {
			err = -errno;
			err = -errno;
		printk(UM_KERN_ERR "mcast_open: IP_MULTICAST_LOOP failed, "
			printk(UM_KERN_ERR "umcast_open: IP_MULTICAST_LOOP "
		       "error = %d\n", errno);
			       "failed, error = %d\n", errno);
			goto out_close;
			goto out_close;
		}
		}
	}


	/* bind socket to mcast address */
	/* bind socket to the address */
	if (bind(fd, (struct sockaddr *) sin, sizeof(*sin)) < 0) {
	if (bind(fd, (struct sockaddr *) lsin, sizeof(*lsin)) < 0) {
		err = -errno;
		err = -errno;
		printk(UM_KERN_ERR "mcast_open : data bind failed, "
		printk(UM_KERN_ERR "umcast_open : data bind failed, "
		       "errno = %d\n", errno);
		       "errno = %d\n", errno);
		goto out_close;
		goto out_close;
	}
	}


	if (!pri->unicast) {
		/* subscribe to the multicast group */
		/* subscribe to the multicast group */
	mreq.imr_multiaddr.s_addr = sin->sin_addr.s_addr;
		mreq.imr_multiaddr.s_addr = lsin->sin_addr.s_addr;
		mreq.imr_interface.s_addr = 0;
		mreq.imr_interface.s_addr = 0;
		if (setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP,
		if (setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP,
			       &mreq, sizeof(mreq)) < 0) {
			       &mreq, sizeof(mreq)) < 0) {
			err = -errno;
			err = -errno;
		printk(UM_KERN_ERR "mcast_open: IP_ADD_MEMBERSHIP failed, "
			printk(UM_KERN_ERR "umcast_open: IP_ADD_MEMBERSHIP "
		       "error = %d\n", errno);
			       "failed, error = %d\n", errno);
		printk(UM_KERN_ERR "There appears not to be a multicast-"
			printk(UM_KERN_ERR "There appears not to be a "
		       "capable network interface on the host.\n");
			       "multicast-capable network interface on the "
		printk(UM_KERN_ERR "eth0 should be configured in order to use "
			       "host.\n");
		       "the multicast transport.\n");
			printk(UM_KERN_ERR "eth0 should be configured in order "
			       "to use the multicast transport.\n");
			goto out_close;
			goto out_close;
		}
		}
	}


	return fd;
	return fd;


@@ -129,35 +147,38 @@ static int mcast_open(void *data)
	return err;
	return err;
}
}


static void mcast_close(int fd, void *data)
static void umcast_close(int fd, void *data)
{
{
	struct umcast_data *pri = data;

	if (!pri->unicast) {
		struct ip_mreq mreq;
		struct ip_mreq mreq;
	struct mcast_data *pri = data;
		struct sockaddr_in *lsin = pri->listen_addr;
	struct sockaddr_in *sin = pri->mcast_addr;


	mreq.imr_multiaddr.s_addr = sin->sin_addr.s_addr;
		mreq.imr_multiaddr.s_addr = lsin->sin_addr.s_addr;
		mreq.imr_interface.s_addr = 0;
		mreq.imr_interface.s_addr = 0;
		if (setsockopt(fd, SOL_IP, IP_DROP_MEMBERSHIP,
		if (setsockopt(fd, SOL_IP, IP_DROP_MEMBERSHIP,
			       &mreq, sizeof(mreq)) < 0) {
			       &mreq, sizeof(mreq)) < 0) {
		printk(UM_KERN_ERR "mcast_open: IP_DROP_MEMBERSHIP failed, "
			printk(UM_KERN_ERR "umcast_close: IP_DROP_MEMBERSHIP "
		       "error = %d\n", errno);
			       "failed, error = %d\n", errno);
		}
	}
	}


	close(fd);
	close(fd);
}
}


int mcast_user_write(int fd, void *buf, int len, struct mcast_data *pri)
int umcast_user_write(int fd, void *buf, int len, struct umcast_data *pri)
{
{
	struct sockaddr_in *data_addr = pri->mcast_addr;
	struct sockaddr_in *data_addr = pri->remote_addr;


	return net_sendto(fd, buf, len, data_addr, sizeof(*data_addr));
	return net_sendto(fd, buf, len, data_addr, sizeof(*data_addr));
}
}


const struct net_user_info mcast_user_info = {
const struct net_user_info umcast_user_info = {
	.init		= mcast_user_init,
	.init	= umcast_user_init,
	.open		= mcast_open,
	.open	= umcast_open,
	.close	 	= mcast_close,
	.close	= umcast_close,
	.remove	 	= mcast_remove,
	.remove	= umcast_remove,
	.add_address	= NULL,
	.add_address	= NULL,
	.delete_address = NULL,
	.delete_address = NULL,
	.mtu	= ETH_MAX_PACKET,
	.mtu	= ETH_MAX_PACKET,
Loading