Virtual ethernet device (v.4)
Subsystems (2)
PATCH 1/1 Virtual ethernet device (v.4)
Veth stands for Virtual ETHernet. It is a simple tunnel driver that works at the link layer and looks like a pair of ethernet devices interconnected with each other.
Mainly it allows to communicate between network namespaces but it can be used as is as well. E.g. one may join to bridged networking segments together.
Eric recently sent a similar driver called etun with the sysfs
interface. This implementation uses another interface - the RTM_NRELINK message introduced by Patric.
The newlink callback is organized that way to make it easy to create the peer device in the separate namespace when we have them in kernel.
Many thanks to Patrick for reviewing the patches and his advises on how to make driver cleaner.
Changes from v.3:
* Reserved place for struct ifinfomsg in IFLA_INFO_DATA part of the packet. This is not used yet, but may be in the future.
Changes from v.2.1:
* Made the generic routine for link creation to be used by veth driver, any other tunnel driver that needs to create several devices at once and rtnl_newlink() code.
Changes from v.2:
* Rebase over latest netdev tree. No actual changes;
* Small code rework.
Changes from v.1:
* Per-cpu statistics;
* Standard convention for nla policy names;
* Module alias added;
* Xmit function fixes noticed by Patric;
* Code cleanup.
The patch for an ip utility is also provided.
PATCH 1/2 Introduce the generic rtnl_create_link()
This routine gets the parsed rtnl attributes and creates a new link with generic info (IFLA_LINKINFO policy). Its intention
is to help the drivers, that need to create several links at once (like VETH).
This is nothing but a copy-paste-ed part of rtnl_newlink() function that is responsible for creation of new device.
---
include/net/rtnetlink.h | 4 ++net/core/rtnetlink.c | 83 ++++++++++++++++++++++++++++++------------------
2 files changed, 57 insertions(+), 30 deletions(-)
include/net/rtnetlink.h +0 -0
@@ -78,6 +78,10 @@ extern void __rtnl_link_unregister(struc
extern int rtnl_link_register(struct rtnl_link_ops *ops);
extern void rtnl_link_unregister(struct rtnl_link_ops *ops);
+extern struct net_device *rtnl_create_link(char *ifname,
+ const struct rtnl_link_ops *ops, struct nlattr *tb[]);
+extern const struct nla_policy ifla_policy[IFLA_MAX+1]; +
#define MODULE_ALIAS_RTNL_LINK(kind) MODULE_ALIAS("rtnl-link-" kind)
#endif
net/core/rtnetlink.c +0 -0
@@ -714,7 +714,7 @@ cont:
return skb->len; }
-static const struct nla_policy ifla_policy[IFLA_MAX+1] = {
+const struct nla_policy ifla_policy[IFLA_MAX+1] = {
[IFLA_IFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ-1 },
[IFLA_ADDRESS] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
[IFLA_BROADCAST] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
@@ -941,6 +941,50 @@ static int rtnl_dellink(struct sk_buff *
return 0;
}+struct net_device *rtnl_create_link(char *ifname,
+ const struct rtnl_link_ops *ops, struct nlattr *tb[])
+{
+ int err;
+ struct net_device *dev;
+
+ err = -ENOMEM;
+ dev = alloc_netdev(ops->priv_size, ifname, ops->setup);
+ if (!dev)
+ goto err;
+
+ if (strchr(dev->name, '%')) {
+ err = dev_alloc_name(dev, dev->name);
+ if (err < 0)
+ goto err_free;
+ }
+
+ dev->rtnl_link_ops = ops;
+
+ if (tb[IFLA_MTU])
+ dev->mtu = nla_get_u32(tb[IFLA_MTU]);
+ if (tb[IFLA_ADDRESS])
+ memcpy(dev->dev_addr, nla_data(tb[IFLA_ADDRESS]),
+ nla_len(tb[IFLA_ADDRESS]));
+ if (tb[IFLA_BROADCAST])
+ memcpy(dev->broadcast, nla_data(tb[IFLA_BROADCAST]),
+ nla_len(tb[IFLA_BROADCAST]));
+ if (tb[IFLA_TXQLEN])
+ dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]);
+ if (tb[IFLA_WEIGHT])
+ dev->weight = nla_get_u32(tb[IFLA_WEIGHT]);
+ if (tb[IFLA_OPERSTATE])
+ set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE]));
+ if (tb[IFLA_LINKMODE])
+ dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]);
+
+ return dev;
+
+err_free:
+ free_netdev(dev);
+err:
+ return ERR_PTR(err);
+}
+
static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
{
const struct rtnl_link_ops *ops;@@ -1051,40 +1095,17 @@ replay:
if (!ifname[0]) snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind);
- dev = alloc_netdev(ops->priv_size, ifname, ops->setup);
- if (!dev)
- return -ENOMEM;
-
- if (strchr(dev->name, '%')) {
- err = dev_alloc_name(dev, dev->name);
- if (err < 0)
- goto err_free;
- }
- dev->rtnl_link_ops = ops;
- if (tb[IFLA_MTU])
- dev->mtu = nla_get_u32(tb[IFLA_MTU]);
- if (tb[IFLA_ADDRESS])
- memcpy(dev->dev_addr, nla_data(tb[IFLA_ADDRESS]),
- nla_len(tb[IFLA_ADDRESS]));
- if (tb[IFLA_BROADCAST])
- memcpy(dev->broadcast, nla_data(tb[IFLA_BROADCAST]),
- nla_len(tb[IFLA_BROADCAST]));
- if (tb[IFLA_TXQLEN])
- dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]);
- if (tb[IFLA_WEIGHT])
- dev->weight = nla_get_u32(tb[IFLA_WEIGHT]);
- if (tb[IFLA_OPERSTATE])
- set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE]));
- if (tb[IFLA_LINKMODE])
- dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]);
+ dev = rtnl_create_link(ifname, ops, tb);
- if (ops->newlink)
+ if (IS_ERR(dev))
+ err = PTR_ERR(dev);
+ else if (ops->newlink)
err = ops->newlink(dev, tb, data); else err = register_netdevice(dev);
-err_free:
- if (err < 0)
+
+ if (err < 0 && !IS_ERR(dev))
free_netdev(dev); return err; }
@@ -1333,3 +1354,5 @@ EXPORT_SYMBOL(rtnl_unlock);EXPORT_SYMBOL(rtnl_unicast);EXPORT_SYMBOL(rtnl_notify);EXPORT_SYMBOL(rtnl_set_sk_err);
+EXPORT_SYMBOL(rtnl_create_link);
+EXPORT_SYMBOL(ifla_policy);
PATCH 2/2 Virtual ethernet device driver
In reply to Pavel EmelyanovVeth stands for Virtual ETHernet. It is a simple tunnel driver that works at the link layer and looks like a pair of ethernet devices interconnected with each other.
Mainly it allows to communicate between network namespaces but it can be used as is as well.
The newlink callback is organized that way to make it easy to create the peer device in the separate namespace when we have them in kernel.
This implementation uses another interface - the RTM_NRELINK message introduced by Patric.
---
drivers/net/Kconfig | 6 drivers/net/Makefile | 1 drivers/net/veth.c | 475 +++++++++++++++++++++++++++++++++++++++++++++++++++include/net/veth.h | 12 +
4 files changed, 494 insertions(+)
drivers/net/Kconfig +0 -0
@@ -134,6 +134,12 @@ config TUN
If you don't know what to use this for, you don't need it.
+config VETH
+ tristate "Virtual ethernet device"
+ ---help---
+ The device is an ethernet tunnel. Devices are created in pairs. When
+ one end receives the packet it appears on its pair and vice versa.
+
config NET_SB1000
tristate "General Instruments Surfboard 1000" depends on PNP
drivers/net/Makefile +0 -0
@@ -189,6 +189,7 @@ obj-$(CONFIG_MACSONIC) += macsonic.o
obj-$(CONFIG_MACMACE) += macmace.o
obj-$(CONFIG_MAC89x0) += mac89x0.o
obj-$(CONFIG_TUN) += tun.o
+obj-$(CONFIG_VETH) += veth.o
obj-$(CONFIG_NET_NETX) += netx-eth.o
obj-$(CONFIG_DL2K) += dl2k.o
obj-$(CONFIG_R8169) += r8169.o
drivers/net/veth.c new file +475 -0
475 lines not on this page · raw message
include/net/veth.h new file +12 -0
@@ -0,0 +1,12 @@ +#ifndef __NET_VETH_H_ +#define __NET_VETH_H_ + +enum { +VETH_INFO_UNSPEC , +VETH_INFO_PEER , + + __VETH_INFO_MAX +#define VETH_INFO_MAX (__VETH_INFO_MAX - 1) +}; + +#endif
PATCH 1/1 Module for ip utility to support veth device (v.3)
In reply to Pavel EmelyanovThe usage is
# ip link add [name] type veth [device parameters] peer [name <name> <other device params>]
This consists of two parts:
1/2 makes some copy-paste changes in ip/iplink.c for generic CLI attributes parsing,
2/2 the module itself.
PATCH 1/2 Introduce iplink_parse() routine
This routine parses CLI attributes, describing generic link parameters such as name, address, etc.
This is mostly copy-pasted from iplink_modify().
---
include/utils.h | 3 +ip/iplink.c | 127 ++++++++++++++++++++++++++++++++------------------------
2 files changed, 76 insertions(+), 54 deletions(-)
include/utils.h +0 -0
@@ -146,4 +146,7 @@ extern int cmdlineno;
extern size_t getcmdline(char **line, size_t *len, FILE *in); extern int makeargs(char *line, char *argv[], int maxargs);
+struct iplink_req;
+int iplink_parse(int argc, char **argv, struct iplink_req *req,
+ char **name, char **type, char **link, char **dev);
#endif /* __UTILS_H__ */
ip/iplink.c +0 -0
@@ -142,140 +142,159 @@ static int iplink_have_newlink(void)
}
#endif /* ! IPLINK_IOCTL_COMPAT */
-static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv) +struct iplink_req {
+ struct nlmsghdr n;
+ struct ifinfomsg i;
+ char buf[1024];
+};
+
+int iplink_parse(int argc, char **argv, struct iplink_req *req,
+ char **name, char **type, char **link, char **dev)
{
+ int ret, len;
+ char abuf[32]; int qlen = -1; int mtu = -1;
- int len;
- char abuf[32];
- char *dev = NULL;
- char *name = NULL;
- char *link = NULL;
- char *type = NULL;
- struct link_util *lu = NULL;
- struct {
- struct nlmsghdr n;
- struct ifinfomsg i;
- char buf[1024];
- } req;
- memset(&req, 0, sizeof(req));
-
- req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
- req.n.nlmsg_flags = NLM_F_REQUEST|flags;
- req.n.nlmsg_type = cmd;
- req.i.ifi_family = preferred_family;
+ ret = argc;
while (argc > 0) {
if (strcmp(*argv, "up") == 0) {
- req.i.ifi_change |= IFF_UP;
- req.i.ifi_flags |= IFF_UP;
+ req->i.ifi_change |= IFF_UP;
+ req->i.ifi_flags |= IFF_UP;
} else if (strcmp(*argv, "down") == 0) {
- req.i.ifi_change |= IFF_UP;
- req.i.ifi_flags &= ~IFF_UP;
+ req->i.ifi_change |= IFF_UP;
+ req->i.ifi_flags &= ~IFF_UP;
} else if (strcmp(*argv, "name") == 0) {
NEXT_ARG();
- name = *argv;
+ *name = *argv;
} else if (matches(*argv, "link") == 0) {
NEXT_ARG();
- link = *argv;
+ *link = *argv;
} else if (matches(*argv, "address") == 0) {
NEXT_ARG();
len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
- addattr_l(&req.n, sizeof(req), IFLA_ADDRESS, abuf, len);
+ addattr_l(&req->n, sizeof(*req), IFLA_ADDRESS, abuf, len);
} else if (matches(*argv, "broadcast") == 0 ||
- strcmp(*argv, "brd") == 0) {
+ strcmp(*argv, "brd") == 0) {
NEXT_ARG();
len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
- addattr_l(&req.n, sizeof(req), IFLA_BROADCAST, abuf, len);
+ addattr_l(&req->n, sizeof(*req), IFLA_BROADCAST, abuf, len);
} else if (matches(*argv, "txqueuelen") == 0 ||
- strcmp(*argv, "qlen") == 0 ||
- matches(*argv, "txqlen") == 0) {
+ strcmp(*argv, "qlen") == 0 ||
+ matches(*argv, "txqlen") == 0) {
NEXT_ARG();
if (qlen != -1)
duparg("txqueuelen", *argv);
if (get_integer(&qlen, *argv, 0))
invarg("Invalid \"txqueuelen\" value\n", *argv);
- addattr_l(&req.n, sizeof(req), IFLA_TXQLEN, &qlen, 4);
+ addattr_l(&req->n, sizeof(*req), IFLA_TXQLEN, &qlen, 4);
} else if (strcmp(*argv, "mtu") == 0) {
NEXT_ARG();
if (mtu != -1)
duparg("mtu", *argv);
if (get_integer(&mtu, *argv, 0))
invarg("Invalid \"mtu\" value\n", *argv);
- addattr_l(&req.n, sizeof(req), IFLA_MTU, &mtu, 4);
+ addattr_l(&req->n, sizeof(*req), IFLA_MTU, &mtu, 4);
} else if (strcmp(*argv, "multicast") == 0) {
NEXT_ARG();
- req.i.ifi_change |= IFF_MULTICAST;
+ req->i.ifi_change |= IFF_MULTICAST;
if (strcmp(*argv, "on") == 0) {
- req.i.ifi_flags |= IFF_MULTICAST;
+ req->i.ifi_flags |= IFF_MULTICAST;
} else if (strcmp(*argv, "off") == 0) {
- req.i.ifi_flags &= ~IFF_MULTICAST;
+ req->i.ifi_flags &= ~IFF_MULTICAST;
} else
return on_off("multicast");
} else if (strcmp(*argv, "allmulticast") == 0) {
NEXT_ARG();
- req.i.ifi_change |= IFF_ALLMULTI;
+ req->i.ifi_change |= IFF_ALLMULTI;
if (strcmp(*argv, "on") == 0) {
- req.i.ifi_flags |= IFF_ALLMULTI;
+ req->i.ifi_flags |= IFF_ALLMULTI;
} else if (strcmp(*argv, "off") == 0) {
- req.i.ifi_flags &= ~IFF_ALLMULTI;
+ req->i.ifi_flags &= ~IFF_ALLMULTI;
} else
return on_off("allmulticast");
} else if (strcmp(*argv, "promisc") == 0) {
NEXT_ARG();
- req.i.ifi_change |= IFF_PROMISC;
+ req->i.ifi_change |= IFF_PROMISC;
if (strcmp(*argv, "on") == 0) {
- req.i.ifi_flags |= IFF_PROMISC;
+ req->i.ifi_flags |= IFF_PROMISC;
} else if (strcmp(*argv, "off") == 0) {
- req.i.ifi_flags &= ~IFF_PROMISC;
+ req->i.ifi_flags &= ~IFF_PROMISC;
} else
return on_off("promisc");
} else if (strcmp(*argv, "trailers") == 0) {
NEXT_ARG();
- req.i.ifi_change |= IFF_NOTRAILERS;
+ req->i.ifi_change |= IFF_NOTRAILERS;
if (strcmp(*argv, "off") == 0) {
- req.i.ifi_flags |= IFF_NOTRAILERS;
+ req->i.ifi_flags |= IFF_NOTRAILERS;
} else if (strcmp(*argv, "on") == 0) {
- req.i.ifi_flags &= ~IFF_NOTRAILERS;
+ req->i.ifi_flags &= ~IFF_NOTRAILERS;
} else
return on_off("trailers");
} else if (strcmp(*argv, "arp") == 0) {
NEXT_ARG();
- req.i.ifi_change |= IFF_NOARP;
+ req->i.ifi_change |= IFF_NOARP;
if (strcmp(*argv, "on") == 0) {
- req.i.ifi_flags &= ~IFF_NOARP;
+ req->i.ifi_flags &= ~IFF_NOARP;
} else if (strcmp(*argv, "off") == 0) {
- req.i.ifi_flags |= IFF_NOARP;
+ req->i.ifi_flags |= IFF_NOARP;
} else
return on_off("noarp");
#ifdef IFF_DYNAMIC
} else if (matches(*argv, "dynamic") == 0) {
NEXT_ARG();
- req.i.ifi_change |= IFF_DYNAMIC;
+ req->i.ifi_change |= IFF_DYNAMIC;
if (strcmp(*argv, "on") == 0) {
- req.i.ifi_flags |= IFF_DYNAMIC;
+ req->i.ifi_flags |= IFF_DYNAMIC;
} else if (strcmp(*argv, "off") == 0) {
- req.i.ifi_flags &= ~IFF_DYNAMIC;
+ req->i.ifi_flags &= ~IFF_DYNAMIC;
} else
return on_off("dynamic");
#endif
} else if (matches(*argv, "type") == 0) {
NEXT_ARG();
- type = *argv;
+ *type = *argv;
argc--; argv++;
break;
} else {
- if (strcmp(*argv, "dev") == 0) {
+ if (strcmp(*argv, "dev") == 0) {
NEXT_ARG();
}
- if (dev)
+ if (*dev)
duparg2("dev", *argv);
- dev = *argv;
+ *dev = *argv;
}
argc--; argv++;
}+ return ret - argc;
+}
+
+static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv) +{
+ int len;
+ char *dev = NULL;
+ char *name = NULL;
+ char *link = NULL;
+ char *type = NULL;
+ struct link_util *lu = NULL;
+ struct iplink_req req;
+ int ret;
+
+ memset(&req, 0, sizeof(req));
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+ req.n.nlmsg_flags = NLM_F_REQUEST|flags;
+ req.n.nlmsg_type = cmd;
+ req.i.ifi_family = preferred_family;
+
+ ret = iplink_parse(argc, argv, &req, &name, &type, &link, &dev);
+ if (ret < 0)
+ return ret;
+
+ argc -= ret;
+ argv += ret;
ll_init_map(&rth);
if (type) {PATCH 2/2 Module for ip utility to support veth device
In reply to Pavel EmelyanovThe link_veth.so itself.
---
Makefile | 6 ++++- link_veth.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ veth.h | 12 +++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-)
ip/Makefile +0 -0
@@ -8,8 +8,9 @@ RTMONOBJ=rtmon.o
ALLOBJ=$(IPOBJ) $(RTMONOBJ)
SCRIPTS=ifcfg rtpr routel routef
TARGETS=ip rtmon
+LIBS=link_veth.so
-all: $(TARGETS) $(SCRIPTS)
+all: $(TARGETS) $(SCRIPTS) $(LIBS)
ip: $(IPOBJ) $(LIBNETLINK) $(LIBUTIL)
@@ -24,3 +25,6 @@ clean:
LDLIBS += -ldl
LDFLAGS += -Wl,-export-dynamic
+
+%.so: %.c
+ $(CC) $(CFLAGS) -shared $< -o $@
ip/link_veth.c new file +63 -0
63 lines not on this page · raw message
ip/veth.h new file +12 -0
@@ -0,0 +1,12 @@ +#ifndef __NET_VETH_H__ +#define __NET_VETH_H__ + +enum { +VETH_INFO_UNSPEC , +VETH_INFO_PEER , + + __VETH_INFO_MAX +#define VETH_INFO_MAX (__VETH_INFO_MAX - 1) +}; + +#endif
Hi, David.
What are your plans about this driver?
Thanks,
Pavel
Quoted 42 lines
Veth stands for Virtual ETHernet. It is a simple tunnel driver that works at the link layer and looks like a pair of ethernet devices interconnected with each other.
Mainly it allows to communicate between network namespaces but it can be used as is as well. E.g. one may join to bridged networking segments together.
Eric recently sent a similar driver called etun with the sysfs
interface. This implementation uses another interface - theRTM_NRELINKmessage introduced by Patric.The newlink callback is organized that way to make it easy to create the peer device in the separate namespace when we have them in kernel.
Many thanks to Patrick for reviewing the patches and his advises on how to make driver cleaner.
Changes from v.3:
* Reserved place for struct ifinfomsg inIFLA_INFO_DATApart of the packet. This is not used yet, but may be in the future.Changes from v.2.1:
* Made the generic routine for link creation to be used by veth driver, any other tunnel driver that needs to create several devices at once andrtnl_newlink()code.Changes from v.2:
* Rebase over latest netdev tree. No actual changes;
* Small code rework.Changes from v.1:
* Per-cpu statistics;
* Standard convention for nla policy names;
* Module alias added;
* Xmit function fixes noticed by Patric;
* Code cleanup.The patch for an ip utility is also provided.
Signed-off-by Pavel Emelianov <[email protected]>Acked-by Patrick McHardy <[email protected]>
David Miller
maintainerFrom: Pavel Emelyanov <[email protected]>
Date: Wed, 08 Aug 2007 14:42:50 +0400
Quoted 1 line
What are your plans about this driver?
I've added it to my net-2.6.24 which I'm building to night.