netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Pavel Emelianov <xemul@sw.ru>
To: David Miller <davem@davemloft.net>,
	Patrick McHardy <kaber@trash.net>,
	Stephen Hemminger <shemminger@linux-foundation.org>
Cc: Ben Greear <greearb@candelatech.com>,
	"Eric W. Biederman" <ebiederm@xmission.com>,
	Linux Netdev List <netdev@vger.kernel.org>,
	Linux Containers <containers@lists.osdl.org>,
	Kirill Korotaev <dev@sw.ru>,
	Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>,
	devel@openvz.org
Subject: [PATCH] Make ip utility veth driver aware
Date: Wed, 02 May 2007 14:57:57 +0400	[thread overview]
Message-ID: <46386EB5.1080309@sw.ru> (raw)
In-Reply-To: <46386DFB.7090109@sw.ru>

The new command is called "veth" with the following syntax:
* ip veth add <dev1> <dev2>
  creates interconnected pair of veth devices.
* ip veth del <dev>
  destroys the pair of veth devices, where <dev> is either
  <dev1> or <dev2> used to create the pair.

One question that is to be solved is whether or not to create
a hard-coded netlink family for veth driver. Without it the 
family resolution code has to be moved to general place in ip
utility (by now it is copy-paste-ed from one file to another
till final decision).

Signed-off-by: Pavel Emelianov <xemul@openvz.org>

---

diff --git a/ip/Makefile b/ip/Makefile
index a749993..864e04e 100644
--- a/ip/Makefile
+++ b/ip/Makefile
@@ -1,7 +1,7 @@
 IPOBJ=ip.o ipaddress.o iproute.o iprule.o \
     rtm_map.o iptunnel.o ip6tunnel.o tunnel.o ipneigh.o ipntable.o iplink.o \
     ipmaddr.o ipmonitor.o ipmroute.o ipprefix.o \
-    ipxfrm.o xfrm_state.o xfrm_policy.o xfrm_monitor.o
+    ipxfrm.o xfrm_state.o xfrm_policy.o xfrm_monitor.o veth.o
 
 RTMONOBJ=rtmon.o
 
diff --git a/ip/ip.c b/ip/ip.c
index c084292..d3d3a8a 100644
--- a/ip/ip.c
+++ b/ip/ip.c
@@ -27,6 +27,7 @@
 #include "SNAPSHOT.h"
 #include "utils.h"
 #include "ip_common.h"
+#include "veth.h"
 
 int preferred_family = AF_UNSPEC;
 int show_stats = 0;
@@ -46,7 +47,7 @@ static void usage(void)
 "Usage: ip [ OPTIONS ] OBJECT { COMMAND | help }\n"
 "       ip [ -force ] [-batch filename\n"
 "where  OBJECT := { link | addr | route | rule | neigh | ntable | tunnel |\n"
-"                   maddr | mroute | monitor | xfrm }\n"
+"                   maddr | mroute | monitor | xfrm | veth }\n"
 "       OPTIONS := { -V[ersion] | -s[tatistics] | -r[esolve] |\n"
 "                    -f[amily] { inet | inet6 | ipx | dnet | link } |\n"
 "                    -o[neline] | -t[imestamp] }\n");
@@ -76,6 +77,7 @@ static const struct cmd {
 	{ "monitor",	do_ipmonitor },
 	{ "xfrm",	do_xfrm },
 	{ "mroute",	do_multiroute },
+	{ "veth",	do_veth },
 	{ "help",	do_help },
 	{ 0 }
 };
diff --git a/ip/veth.c b/ip/veth.c
new file mode 100644
index 0000000..d4eecc8
--- /dev/null
+++ b/ip/veth.c
@@ -0,0 +1,196 @@
+/*
+ * veth.c	       "ethernet tunnel"
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ *
+ * Authors:	Pavel Emelianov, <xemul@openvz.org>
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <linux/genetlink.h>
+
+#include "utils.h"
+#include "veth.h"
+
+#define GENLMSG_DATA(glh)       ((void *)(NLMSG_DATA(glh) + GENL_HDRLEN))
+#define NLA_DATA(na)            ((void *)((char*)(na) + NLA_HDRLEN))
+
+static int do_veth_help(void)
+{
+	fprintf(stderr, "Usage: ip veth add DEVICE PEER_NAME\n");
+	fprintf(stderr, "               del DEVICE\n");
+	exit(-1);
+}
+
+static int genl_ctrl_resolve_family(const char *family)
+{
+	struct rtnl_handle rth;
+	struct nlmsghdr *nlh;
+	struct genlmsghdr *ghdr;
+	int ret = 0;
+	struct {
+		struct nlmsghdr         n;
+		char                    buf[4096];
+	} req;
+
+	memset(&req, 0, sizeof(req));
+
+	nlh = &req.n;
+	nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
+	nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+	nlh->nlmsg_type = GENL_ID_CTRL;
+
+	ghdr = NLMSG_DATA(&req.n);
+	ghdr->cmd = CTRL_CMD_GETFAMILY;
+
+	if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC) < 0) {
+		fprintf(stderr, "Cannot open generic netlink socket\n");
+		exit(1);
+	}
+
+	addattr_l(nlh, 128, CTRL_ATTR_FAMILY_NAME, family, strlen(family) + 1);
+
+	if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL) < 0) {
+		fprintf(stderr, "Error talking to the kernel\n");
+		goto errout;
+	}
+
+	{
+		struct rtattr *tb[CTRL_ATTR_MAX + 1];
+		struct genlmsghdr *ghdr = NLMSG_DATA(nlh);
+		int len = nlh->nlmsg_len;
+		struct rtattr *attrs;
+
+		if (nlh->nlmsg_type !=  GENL_ID_CTRL) {
+			fprintf(stderr, "Not a controller message, nlmsg_len=%d "
+				"nlmsg_type=0x%x\n", nlh->nlmsg_len, nlh->nlmsg_type);
+			goto errout;
+		}
+
+		if (ghdr->cmd != CTRL_CMD_NEWFAMILY) {
+			fprintf(stderr, "Unkown controller command %d\n", ghdr->cmd);
+			goto errout;
+		}
+
+		len -= NLMSG_LENGTH(GENL_HDRLEN);
+
+		if (len < 0) {
+			fprintf(stderr, "wrong controller message len %d\n", len);
+			return -1;
+		}
+
+		attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN);
+		parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len);
+
+		if (tb[CTRL_ATTR_FAMILY_ID] == NULL) {
+			fprintf(stderr, "Missing family id TLV\n");
+			goto errout;
+		}
+
+		ret = *(__u16 *) RTA_DATA(tb[CTRL_ATTR_FAMILY_ID]);
+	}
+
+errout:
+	rtnl_close(&rth);
+	return ret;
+}
+
+static int do_veth_operate(char *dev, char *peer, int cmd)
+{
+	struct rtnl_handle rth;
+	struct nlmsghdr *nlh;
+	struct genlmsghdr *ghdr;
+	struct nlattr *attr;
+	struct  {
+		struct nlmsghdr n;
+		struct genlmsghdr h;
+		char bug[1024];
+	} req;
+	int family, len;
+	int err = 0;
+
+	family = genl_ctrl_resolve_family("veth");
+	if (family == 0) {
+		fprintf(stderr, "veth: Can't resolve family\n");
+		exit(1);
+	}
+
+	if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC) < 0)
+		exit(1);
+
+	nlh = &req.n;
+	nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
+	nlh->nlmsg_flags = NLM_F_REQUEST;
+	nlh->nlmsg_type = family;
+	nlh->nlmsg_seq = 0;
+
+	ghdr = &req.h;
+	ghdr->cmd = cmd;
+
+	attr = (struct nlattr *) GENLMSG_DATA(&req);
+	len = strlen(dev);
+	attr->nla_type = VETH_ATTR_DEVNAME;
+	attr->nla_len = len + 1 + NLA_HDRLEN;
+	memcpy(NLA_DATA(attr), dev, len);
+	nlh->nlmsg_len += NLMSG_ALIGN(attr->nla_len);
+
+	if (peer) {
+		attr = (struct nlattr *)((char *)attr +
+				NLMSG_ALIGN(attr->nla_len));
+		len = strlen(peer);
+		attr->nla_type = VETH_ATTR_PEERNAME;
+		attr->nla_len = len + 1 + NLA_HDRLEN;
+		memcpy(NLA_DATA(attr), peer, len);
+		nlh->nlmsg_len += NLMSG_ALIGN(attr->nla_len);
+	}
+
+	if (rtnl_send(&rth, (char *) &req, nlh->nlmsg_len) < 0) {
+		err = -1;
+		fprintf(stderr, "Error talking to the kernel (add)\n");
+	}
+
+	rtnl_close(&rth);
+	return err;
+}
+
+static int do_veth_add(int argc, char **argv)
+{
+	if (argc < 2)
+		return do_veth_help();
+
+	return do_veth_operate(argv[0], argv[1], VETH_CMD_ADD);
+}
+
+static int do_veth_del(int argc, char **argv)
+{
+	char *name;
+
+	if (argc < 1)
+		return do_veth_help();
+
+	return do_veth_operate(argv[0], NULL, VETH_CMD_DEL);
+}
+
+int do_veth(int argc, char **argv)
+{
+	if (argc == 0)
+		return do_veth_help();
+
+	if (strcmp(*argv, "add") == 0 || strcmp(*argv, "a") == 0)
+		return do_veth_add(argc - 1, argv + 1);
+	if (strcmp(*argv, "del") == 0 || strcmp(*argv, "d") == 0)
+		return do_veth_del(argc - 1, argv + 1);
+	if (strcmp(*argv, "help") == 0)
+		return do_veth_help();
+
+	fprintf(stderr, "Command \"%s\" is unknown, try \"ip veth help\".\n", *argv);
+	exit(-1);
+}
diff --git a/ip/veth.h b/ip/veth.h
new file mode 100644
index 0000000..4d7b357
--- /dev/null
+++ b/ip/veth.h
@@ -0,0 +1,17 @@
+int do_veth(int argc, char **argv);
+
+enum {
+	VETH_CMD_UNSPEC, 
+	VETH_CMD_ADD, 
+	VETH_CMD_DEL,
+
+	VETH_CMD_MAX
+};
+
+enum {
+	VETH_ATTR_UNSPEC,
+	VETH_ATTR_DEVNAME,
+	VETH_ATTR_PEERNAME,
+
+	VETH_ATTR_MAX
+};

  reply	other threads:[~2007-05-02 10:55 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-05-02 10:54 [PATCH] Virtual ethernet device (tunnel) Pavel Emelianov
2007-05-02 10:57 ` Pavel Emelianov [this message]
2007-05-02 12:07 ` [Devel] " Daniel Lezcano
2007-05-02 12:27   ` Pavel Emelianov
2007-05-02 12:34 ` Patrick McHardy
2007-05-02 12:49   ` jamal
2007-05-02 12:59     ` Patrick McHardy
2007-05-02 13:40       ` Eric W. Biederman
2007-05-02 13:57         ` Patrick McHardy
2007-05-02 16:37 ` Stephen Hemminger
2007-05-02 16:50 ` Ben Greear

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=46386EB5.1080309@sw.ru \
    --to=xemul@sw.ru \
    --cc=containers@lists.osdl.org \
    --cc=davem@davemloft.net \
    --cc=dev@sw.ru \
    --cc=devel@openvz.org \
    --cc=ebiederm@xmission.com \
    --cc=greearb@candelatech.com \
    --cc=kaber@trash.net \
    --cc=kuznet@ms2.inr.ac.ru \
    --cc=netdev@vger.kernel.org \
    --cc=shemminger@linux-foundation.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).