netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [IPROUTE 00/02]: rtnl_link support
@ 2007-06-13 17:02 Patrick McHardy
  2007-06-13 17:02 ` [IPROUTE 01/02]: iplink: use netlink for link configuration Patrick McHardy
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Patrick McHardy @ 2007-06-13 17:02 UTC (permalink / raw)
  To: shemminger; +Cc: netdev, Patrick McHardy

Hi Stephen,

these patches add support for the rtnl_link stuff and VLAN configuration
to iproute. Since the old link configuration was entirely ioctl based and
mixing the two would be really ugly, this patch keeps the old ioctl stuff
guarded by an ifdef (defaults to enabled) and probes for support for
using RTM_NEWLINK. Tested to work properly on both old and patched kernel.

I've added a new -d[etail] flag to ip, the driver specific things are only
printed when it is specified. I did this mainly because I'm not sure how
careful we want to be not to confuse people using sed/awk/... on iproute
output. I would prefer to have the information always shown, but I'll
leave that decision up to you.

Changes since the last post:

- Only call link argument parsing function if arguments are present
- Support xstats dumping
- Add sanitized if_vlan.h file for VLAN flag definition
- Support setting/changing VLAN flags

Please apply, thanks.


 include/linux/if_link.h |   47 +++++++
 include/linux/if_vlan.h |   61 +++++++++
 ip/Makefile             |    4 
 ip/ip.c                 |    5 
 ip/ip_common.h          |   15 ++
 ip/ipaddress.c          |   39 ++++++
 ip/iplink.c             |  311 +++++++++++++++++++++++++++++++++++++++++++++++-
 ip/iplink_vlan.c        |  184 ++++++++++++++++++++++++++++
 8 files changed, 663 insertions(+), 3 deletions(-)

Patrick McHardy (2):
      [IPROUTE]: iplink: use netlink for link configuration
      [IPROUTE]: VLAN support

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [IPROUTE 01/02]: iplink: use netlink for link configuration
  2007-06-13 17:02 [IPROUTE 00/02]: rtnl_link support Patrick McHardy
@ 2007-06-13 17:02 ` Patrick McHardy
  2007-06-13 17:02 ` [IPROUTE 02/02]: VLAN support Patrick McHardy
  2007-06-13 17:48 ` [IPROUTE 00/02]: rtnl_link support Stephen Hemminger
  2 siblings, 0 replies; 6+ messages in thread
From: Patrick McHardy @ 2007-06-13 17:02 UTC (permalink / raw)
  To: shemminger; +Cc: netdev, Patrick McHardy

[IPROUTE]: iplink: use netlink for link configuration

Add support for using netlink for link configuration. Kernel-support is
probed, when not available it falls back to using ioctls.

Signed-off-by: Patrick McHardy <kaber@trash.net>

---
commit 4feb48d12295eb41850c39996f3a8c1dd7909ed5
tree dbb34cf5a9b38adb0c2602a88b09823f922c8a2c
parent b16621cafd599499fdbaa79236266d72a53106bb
author Patrick McHardy <kaber@trash.net> Wed, 13 Jun 2007 14:10:57 +0200
committer Patrick McHardy <kaber@trash.net> Wed, 13 Jun 2007 14:10:57 +0200

 include/linux/if_link.h |   13 ++
 ip/Makefile             |    2 
 ip/ip.c                 |    5 +
 ip/ip_common.h          |   15 ++
 ip/ipaddress.c          |   39 ++++++
 ip/iplink.c             |  311 +++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 382 insertions(+), 3 deletions(-)

diff --git a/include/linux/if_link.h b/include/linux/if_link.h
index 2920e8a..58a48d7 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h
@@ -76,6 +76,8 @@ enum
 #define IFLA_WEIGHT IFLA_WEIGHT
 	IFLA_OPERSTATE,
 	IFLA_LINKMODE,
+	IFLA_LINKINFO,
+#define IFLA_LINKINFO IFLA_LINKINFO
 	__IFLA_MAX
 };
 
@@ -137,4 +139,15 @@ struct ifla_cacheinfo
 	__u32	retrans_time;
 };
 
+enum
+{
+	IFLA_INFO_UNSPEC,
+	IFLA_INFO_KIND,
+	IFLA_INFO_DATA,
+	IFLA_INFO_XSTATS,
+	__IFLA_INFO_MAX,
+};
+
+#define IFLA_INFO_MAX	(__IFLA_INFO_MAX - 1)
+
 #endif /* _LINUX_IF_LINK_H */
diff --git a/ip/Makefile b/ip/Makefile
index a749993..9a5bfe3 100644
--- a/ip/Makefile
+++ b/ip/Makefile
@@ -22,3 +22,5 @@ install: all
 clean:
 	rm -f $(ALLOBJ) $(TARGETS)
 
+LDLIBS	+= -ldl
+LDFLAGS	+= -Wl,-export-dynamic
diff --git a/ip/ip.c b/ip/ip.c
index c084292..4bdb83b 100644
--- a/ip/ip.c
+++ b/ip/ip.c
@@ -30,6 +30,7 @@
 
 int preferred_family = AF_UNSPEC;
 int show_stats = 0;
+int show_details = 0;
 int resolve_hosts = 0;
 int oneline = 0;
 int timestamp = 0;
@@ -47,7 +48,7 @@ static void usage(void)
 "       ip [ -force ] [-batch filename\n"
 "where  OBJECT := { link | addr | route | rule | neigh | ntable | tunnel |\n"
 "                   maddr | mroute | monitor | xfrm }\n"
-"       OPTIONS := { -V[ersion] | -s[tatistics] | -r[esolve] |\n"
+"       OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n"
 "                    -f[amily] { inet | inet6 | ipx | dnet | link } |\n"
 "                    -o[neline] | -t[imestamp] }\n");
 	exit(-1);
@@ -188,6 +189,8 @@ int main(int argc, char **argv)
 		} else if (matches(opt, "-stats") == 0 ||
 			   matches(opt, "-statistics") == 0) {
 			++show_stats;
+		} else if (matches(opt, "-details") == 0) {
+			++show_details;
 		} else if (matches(opt, "-resolve") == 0) {
 			++resolve_hosts;
 		} else if (matches(opt, "-oneline") == 0) {
diff --git a/ip/ip_common.h b/ip/ip_common.h
index 5bfd9b9..39f2507 100644
--- a/ip/ip_common.h
+++ b/ip/ip_common.h
@@ -45,6 +45,21 @@ static inline int rtm_get_table(struct rtmsg *r, struct rtattr **tb)
 
 extern struct rtnl_handle rth;
 
+struct link_util
+{
+	struct link_util	*next;
+	const char		*id;
+	int			maxattr;
+	int			(*parse_opt)(struct link_util *, int, char **,
+					     struct nlmsghdr *);
+	void			(*print_opt)(struct link_util *, FILE *,
+					     struct rtattr *[]);
+	void			(*print_xstats)(struct link_util *, FILE *,
+					     struct rtattr *);
+};
+
+struct link_util *get_link_kind(const char *kind);
+
 #ifndef	INFINITY_LIFE_TIME
 #define     INFINITY_LIFE_TIME      0xFFFFFFFFU
 #endif
diff --git a/ip/ipaddress.c b/ip/ipaddress.c
index 98effa3..da6b270 100644
--- a/ip/ipaddress.c
+++ b/ip/ipaddress.c
@@ -134,6 +134,41 @@ void print_queuelen(char *name)
 		printf("qlen %d", ifr.ifr_qlen);
 }
 
+static void print_linktype(FILE *fp, struct rtattr *tb)
+{
+	struct rtattr *linkinfo[IFLA_INFO_MAX+1];
+	struct link_util *lu;
+	char *kind;
+
+	parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb);
+
+	if (!linkinfo[IFLA_INFO_KIND])
+		return;
+	kind = RTA_DATA(linkinfo[IFLA_INFO_KIND]);
+
+	fprintf(fp, "%s", _SL_);
+	fprintf(fp, "    %s ", kind);
+
+	lu = get_link_kind(kind);
+	if (!lu || !lu->print_opt)
+		return;
+
+	if (1) {
+		struct rtattr *attr[lu->maxattr+1], **data = NULL;
+
+		if (linkinfo[IFLA_INFO_DATA]) {
+			parse_rtattr_nested(attr, lu->maxattr,
+					    linkinfo[IFLA_INFO_DATA]);
+			data = attr;
+		}
+		lu->print_opt(lu, fp, data);
+
+		if (linkinfo[IFLA_INFO_XSTATS] && show_stats &&
+		    lu->print_xstats)
+			lu->print_xstats(lu, fp, linkinfo[IFLA_INFO_XSTATS]);
+	}
+}
+
 int print_linkinfo(const struct sockaddr_nl *who,
 		   struct nlmsghdr *n, void *arg)
 {
@@ -221,6 +256,10 @@ int print_linkinfo(const struct sockaddr_nl *who,
 						      b1, sizeof(b1)));
 		}
 	}
+
+	if (do_link && tb[IFLA_LINKINFO] && show_details)
+		print_linktype(fp, tb[IFLA_LINKINFO]);
+
 	if (do_link && tb[IFLA_STATS] && show_stats) {
 		struct rtnl_link_stats slocal;
 		struct rtnl_link_stats *s = RTA_DATA(tb[IFLA_STATS]);
diff --git a/ip/iplink.c b/ip/iplink.c
index 8f82a08..4060845 100644
--- a/ip/iplink.c
+++ b/ip/iplink.c
@@ -15,6 +15,7 @@
 #include <unistd.h>
 #include <syslog.h>
 #include <fcntl.h>
+#include <dlfcn.h>
 #include <errno.h>
 #include <sys/socket.h>
 #include <linux/if.h>
@@ -31,6 +32,7 @@
 #include "utils.h"
 #include "ip_common.h"
 
+#define IPLINK_IOCTL_COMPAT	1
 
 static void usage(void) __attribute__((noreturn));
 
@@ -62,6 +64,290 @@ static int on_off(char *msg)
 	return -1;
 }
 
+static void *BODY;		/* cached dlopen(NULL) handle */
+static struct link_util *linkutil_list;
+
+struct link_util *get_link_kind(const char *id)
+{
+	void *dlh;
+	char buf[256];
+	struct link_util *l;
+
+	for (l = linkutil_list; l; l = l->next)
+		if (strcmp(l->id, id) == 0)
+			return l;
+
+	snprintf(buf, sizeof(buf), "/usr/lib/ip/link_%s.so", id);
+	dlh = dlopen(buf, RTLD_LAZY);
+	if (dlh == NULL) {
+		/* look in current binary, only open once */
+		dlh = BODY;
+		if (dlh == NULL) {
+			dlh = BODY = dlopen(NULL, RTLD_LAZY);
+			if (dlh == NULL)
+				return NULL;
+		}
+	}
+
+	snprintf(buf, sizeof(buf), "%s_link_util", id);
+	l = dlsym(dlh, buf);
+	if (l == NULL)
+		return NULL;
+
+	l->next = linkutil_list;
+	linkutil_list = l;
+	return l;
+}
+
+#if IPLINK_IOCTL_COMPAT
+static int have_rtnl_newlink = -1;
+
+static int accept_msg(const struct sockaddr_nl *who,
+		      struct nlmsghdr *n, void *arg)
+{
+	struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n);
+
+	if (n->nlmsg_type == NLMSG_ERROR && err->error == -EOPNOTSUPP)
+		have_rtnl_newlink = 0;
+	else
+		have_rtnl_newlink = 1;
+	return -1;
+}
+
+static int iplink_have_newlink(void)
+{
+	struct {
+		struct nlmsghdr		n;
+		struct ifinfomsg	i;
+		char			buf[1024];
+	} req;
+
+	if (have_rtnl_newlink < 0) {
+		memset(&req, 0, sizeof(req));
+
+		req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+		req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
+		req.n.nlmsg_type = RTM_NEWLINK;
+		req.i.ifi_family = AF_UNSPEC;
+
+		rtnl_send(&rth, (char *)&req.n, req.n.nlmsg_len);
+		rtnl_listen(&rth, accept_msg, NULL);
+	}
+	return have_rtnl_newlink;
+}
+#else /* IPLINK_IOCTL_COMPAT */
+static int iplink_have_newlink(void)
+{
+	return 1;
+}
+#endif /* ! IPLINK_IOCTL_COMPAT */
+
+static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
+{
+	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;
+
+	while (argc > 0) {
+		if (strcmp(*argv, "up") == 0) {
+			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;
+		} else if (strcmp(*argv, "name") == 0) {
+			NEXT_ARG();
+			name = *argv;
+		} else if (matches(*argv, "link") == 0) {
+			NEXT_ARG();
+			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);
+		} else if (matches(*argv, "broadcast") == 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);
+		} else if (matches(*argv, "txqueuelen") == 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);
+		} 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);
+		} else if (strcmp(*argv, "multicast") == 0) {
+			NEXT_ARG();
+			req.i.ifi_change |= IFF_MULTICAST;
+			if (strcmp(*argv, "on") == 0) {
+				req.i.ifi_flags |= IFF_MULTICAST;
+			} else if (strcmp(*argv, "off") == 0) {
+				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;
+			if (strcmp(*argv, "on") == 0) {
+				req.i.ifi_flags |= IFF_ALLMULTI;
+			} else if (strcmp(*argv, "off") == 0) {
+				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;
+			if (strcmp(*argv, "on") == 0) {
+				req.i.ifi_flags |= IFF_PROMISC;
+			} else if (strcmp(*argv, "off") == 0) {
+				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;
+			if (strcmp(*argv, "off") == 0) {
+				req.i.ifi_flags |= IFF_NOTRAILERS;
+			} else if (strcmp(*argv, "on") == 0) {
+				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;
+			if (strcmp(*argv, "on") == 0) {
+				req.i.ifi_flags &= ~IFF_NOARP;
+			} else if (strcmp(*argv, "off") == 0) {
+				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;
+			if (strcmp(*argv, "on") == 0) {
+				req.i.ifi_flags |= IFF_DYNAMIC;
+			} else if (strcmp(*argv, "off") == 0) {
+				req.i.ifi_flags &= ~IFF_DYNAMIC;
+			} else
+				return on_off("dynamic");
+#endif
+		} else if (matches(*argv, "type") == 0) {
+			NEXT_ARG();
+			type = *argv;
+			argc--; argv++;
+			break;
+		} else {
+                        if (strcmp(*argv, "dev") == 0) {
+				NEXT_ARG();
+			}
+			if (dev)
+				duparg2("dev", *argv);
+			dev = *argv;
+		}
+		argc--; argv++;
+	}
+
+	ll_init_map(&rth);
+
+	if (type) {
+		struct rtattr *linkinfo = NLMSG_TAIL(&req.n);
+		addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0);
+		addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type,
+			 strlen(type));
+
+		lu = get_link_kind(type);
+		if (lu && argc) {
+			struct rtattr * data = NLMSG_TAIL(&req.n);
+			addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0);
+
+			if (lu->parse_opt &&
+			    lu->parse_opt(lu, argc, argv, &req.n))
+				return -1;
+
+			data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data;
+		} else if (argc) {
+			if (matches(*argv, "help") == 0)
+				usage();
+			fprintf(stderr, "Garbage instead of arguments \"%s ...\". "
+					"Try \"ip link help\".\n", *argv);
+			return -1;
+		}
+		linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
+	}
+
+	if (!(flags & NLM_F_CREATE)) {
+		if (!dev) {
+			fprintf(stderr, "Not enough information: \"dev\" "
+					"argument is required.\n");
+			exit(-1);
+		}
+
+		req.i.ifi_index = ll_name_to_index(dev);
+		if (req.i.ifi_index == 0) {
+			fprintf(stderr, "Cannot find device \"%s\"\n", dev);
+			return -1;
+		}
+	} else {
+		/* Allow "ip link add dev" and "ip link add name" */
+		if (!name)
+			name = dev;
+
+		if (link) {
+			int ifindex;
+
+			ifindex = ll_name_to_index(link);
+			if (ifindex == 0) {
+				fprintf(stderr, "Cannot find device \"%s\"\n",
+					link);
+				return -1;
+			}
+			addattr_l(&req.n, sizeof(req), IFLA_LINK, &ifindex, 4);
+		}
+	}
+
+	if (name) {
+		len = strlen(name) + 1;
+		if (len > IFNAMSIZ)
+			invarg("\"name\" too long\n", *argv);
+		addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, len);
+	}
+
+	if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
+		exit(2);
+
+	return 0;
+}
+
+#if IPLINK_IOCTL_COMPAT
 static int get_ctl_fd(void)
 {
 	int s_errno;
@@ -410,12 +696,33 @@ static int do_set(int argc, char **argv)
 		return do_chflags(dev, flags, mask);
 	return 0;
 }
+#endif /* IPLINK_IOCTL_COMPAT */
 
 int do_iplink(int argc, char **argv)
 {
 	if (argc > 0) {
-		if (matches(*argv, "set") == 0)
-			return do_set(argc-1, argv+1);
+		if (iplink_have_newlink()) {
+			if (matches(*argv, "add") == 0)
+				return iplink_modify(RTM_NEWLINK,
+						     NLM_F_CREATE|NLM_F_EXCL,
+						     argc-1, argv+1);
+			if (matches(*argv, "set") == 0 ||
+			    matches(*argv, "change") == 0)
+				return iplink_modify(RTM_NEWLINK, 0,
+						     argc-1, argv+1);
+			if (matches(*argv, "replace") == 0)
+				return iplink_modify(RTM_NEWLINK,
+						     NLM_F_CREATE|NLM_F_REPLACE,
+						     argc-1, argv+1);
+			if (matches(*argv, "delete") == 0)
+				return iplink_modify(RTM_DELLINK, 0,
+						     argc-1, argv+1);
+		} else {
+#if IPLINK_IOCTL_COMPAT
+			if (matches(*argv, "set") == 0)
+				return do_set(argc-1, argv+1);
+#endif
+		}
 		if (matches(*argv, "show") == 0 ||
 		    matches(*argv, "lst") == 0 ||
 		    matches(*argv, "list") == 0)

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [IPROUTE 02/02]: VLAN support
  2007-06-13 17:02 [IPROUTE 00/02]: rtnl_link support Patrick McHardy
  2007-06-13 17:02 ` [IPROUTE 01/02]: iplink: use netlink for link configuration Patrick McHardy
@ 2007-06-13 17:02 ` Patrick McHardy
  2007-06-13 17:48 ` [IPROUTE 00/02]: rtnl_link support Stephen Hemminger
  2 siblings, 0 replies; 6+ messages in thread
From: Patrick McHardy @ 2007-06-13 17:02 UTC (permalink / raw)
  To: shemminger; +Cc: netdev, Patrick McHardy

[IPROUTE]: VLAN support

---
commit 90727b2bf5b4a7ef9d0638ca80206083b965a0b5
tree 173722acd855b7fe1eb1a5f22cf7706814f72c8f
parent 4feb48d12295eb41850c39996f3a8c1dd7909ed5
author Patrick McHardy <kaber@trash.net> Wed, 13 Jun 2007 18:46:21 +0200
committer Patrick McHardy <kaber@trash.net> Wed, 13 Jun 2007 18:46:21 +0200

 include/linux/if_link.h |   34 +++++++++
 include/linux/if_vlan.h |   61 ++++++++++++++++
 ip/Makefile             |    2 +
 ip/iplink_vlan.c        |  184 +++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 281 insertions(+), 0 deletions(-)

diff --git a/include/linux/if_link.h b/include/linux/if_link.h
index 58a48d7..7e6d15d 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h
@@ -150,4 +150,38 @@ enum
 
 #define IFLA_INFO_MAX	(__IFLA_INFO_MAX - 1)
 
+/* VLAN section */
+
+enum
+{
+	IFLA_VLAN_UNSPEC,
+	IFLA_VLAN_ID,
+	IFLA_VLAN_FLAGS,
+	IFLA_VLAN_EGRESS_QOS,
+	IFLA_VLAN_INGRESS_QOS,
+	__IFLA_VLAN_MAX,
+};
+
+#define IFLA_VLAN_MAX	(__IFLA_VLAN_MAX - 1)
+
+struct ifla_vlan_flags {
+	__u32	flags;
+	__u32	mask;
+};
+
+enum
+{
+	IFLA_VLAN_QOS_UNSPEC,
+	IFLA_VLAN_QOS_MAPPING,
+	__IFLA_VLAN_QOS_MAX
+};
+
+#define IFLA_VLAN_QOS_MAX	(__IFLA_VLAN_QOS_MAX - 1)
+
+struct ifla_vlan_qos_mapping
+{
+	__u32 from;
+	__u32 to;
+};
+
 #endif /* _LINUX_IF_LINK_H */
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
new file mode 100644
index 0000000..4014ba9
--- /dev/null
+++ b/include/linux/if_vlan.h
@@ -0,0 +1,61 @@
+/*
+ * VLAN		An implementation of 802.1Q VLAN tagging.
+ *
+ * Authors:	Ben Greear <greearb@candelatech.com>
+ *
+ *		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.
+ *
+ */
+
+#ifndef _LINUX_IF_VLAN_H_
+#define _LINUX_IF_VLAN_H_
+
+
+/* VLAN IOCTLs are found in sockios.h */
+
+/* Passed in vlan_ioctl_args structure to determine behaviour. */
+enum vlan_ioctl_cmds {
+	ADD_VLAN_CMD,
+	DEL_VLAN_CMD,
+	SET_VLAN_INGRESS_PRIORITY_CMD,
+	SET_VLAN_EGRESS_PRIORITY_CMD,
+	GET_VLAN_INGRESS_PRIORITY_CMD,
+	GET_VLAN_EGRESS_PRIORITY_CMD,
+	SET_VLAN_NAME_TYPE_CMD,
+	SET_VLAN_FLAG_CMD,
+	GET_VLAN_REALDEV_NAME_CMD, /* If this works, you know it's a VLAN device, btw */
+	GET_VLAN_VID_CMD /* Get the VID of this VLAN (specified by name) */
+};
+
+enum vlan_flags {
+	VLAN_FLAG_REORDER_HDR	= 0x1,
+};
+
+enum vlan_name_types {
+	VLAN_NAME_TYPE_PLUS_VID, /* Name will look like:  vlan0005 */
+	VLAN_NAME_TYPE_RAW_PLUS_VID, /* name will look like:  eth1.0005 */
+	VLAN_NAME_TYPE_PLUS_VID_NO_PAD, /* Name will look like:  vlan5 */
+	VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD, /* Name will look like:  eth0.5 */
+	VLAN_NAME_TYPE_HIGHEST
+};
+
+struct vlan_ioctl_args {
+	int cmd; /* Should be one of the vlan_ioctl_cmds enum above. */
+	char device1[24];
+
+        union {
+		char device2[24];
+		int VID;
+		unsigned int skb_priority;
+		unsigned int name_type;
+		unsigned int bind_type;
+		unsigned int flag; /* Matches vlan_dev_info flags */
+        } u;
+
+	short vlan_qos;  
+};
+
+#endif /* !(_LINUX_IF_VLAN_H_) */
diff --git a/ip/Makefile b/ip/Makefile
index 9a5bfe3..b6d8693 100644
--- a/ip/Makefile
+++ b/ip/Makefile
@@ -3,6 +3,8 @@ IPOBJ=ip.o ipaddress.o iproute.o iprule.o \
     ipmaddr.o ipmonitor.o ipmroute.o ipprefix.o \
     ipxfrm.o xfrm_state.o xfrm_policy.o xfrm_monitor.o
 
+IPOBJ += iplink_vlan.o
+
 RTMONOBJ=rtmon.o
 
 ALLOBJ=$(IPOBJ) $(RTMONOBJ)
diff --git a/ip/iplink_vlan.c b/ip/iplink_vlan.c
new file mode 100644
index 0000000..ef05fbc
--- /dev/null
+++ b/ip/iplink_vlan.c
@@ -0,0 +1,184 @@
+/*
+ * iplink_vlan.c	VLAN device support
+ *
+ *              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:     Patrick McHardy <kaber@trash.net>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <linux/if_vlan.h>
+
+#include "rt_names.h"
+#include "utils.h"
+#include "ip_common.h"
+
+static void explain(void)
+{
+	fprintf(stderr,
+		"Usage: ... vlan id VLANID [ FLAG-LIST ]\n"
+		"                          [ ingress-qos-map QOS-MAP ] [ egress-qos-map QOS-MAP ]\n"
+		"\n"
+		"VLANID := 0-4095\n"
+		"FLAG-LIST := [ FLAG-LIST ] FLAG\n"
+		"FLAG := [ reorder_hdr { on | off } ]\n"
+		"QOS-MAP := [ QOS-MAP ] QOS-MAPPING\n"
+		"QOS-MAPPING := FROM:TO\n"
+	);
+}
+
+static int on_off(char *msg)
+{
+	fprintf(stderr, "Error: argument of \"%s\" must be \"on\" or \"off\"\n", msg);
+	return -1;
+}
+
+static int vlan_parse_qos_map(int *argcp, char ***argvp, struct nlmsghdr *n,
+			      int attrtype)
+{
+	int argc = *argcp;
+	char **argv = *argvp;
+	struct ifla_vlan_qos_mapping m;
+	struct rtattr *tail;
+
+	tail = NLMSG_TAIL(n);
+	addattr_l(n, 1024, attrtype, NULL, 0);
+
+	while (argc > 0) {
+		char *colon = strchr(*argv, ':');
+
+		if (!colon)
+			break;
+		*colon = '\0';
+
+		if (get_u32(&m.from, *argv, 0))
+			return 1;
+		if (get_u32(&m.to, colon + 1, 0))
+			return 1;
+		argc--, argv++;
+
+		addattr_l(n, 1024, IFLA_VLAN_QOS_MAPPING, &m, sizeof(m));
+	}
+
+	tail->rta_len = (void *) NLMSG_TAIL(n) - (void *)tail;
+
+	*argcp = argc;
+	*argvp = argv;
+	return 0;
+}
+
+static int vlan_parse_opt(struct link_util *lu, int argc, char **argv,
+			  struct nlmsghdr *n)
+{
+	struct ifla_vlan_flags flags = { 0 };
+	__u16 id;
+
+	while (argc > 0) {
+		if (matches(*argv, "id") == 0) {
+			NEXT_ARG();
+			if (get_u16(&id, *argv, 0))
+				invarg("id is invalid", *argv);
+			addattr_l(n, 1024, IFLA_VLAN_ID, &id, 2);
+		} else if (matches(*argv, "reorder_hdr") == 0) {
+			NEXT_ARG();
+			flags.mask |= VLAN_FLAG_REORDER_HDR;
+			if (strcmp(*argv, "on") == 0)
+				flags.flags |= VLAN_FLAG_REORDER_HDR;
+			else if (strcmp(*argv, "off") == 0)
+				flags.flags &= ~VLAN_FLAG_REORDER_HDR;
+			else
+				return on_off("reorder_hdr");
+		} else if (matches(*argv, "ingress-qos-map") == 0) {
+			NEXT_ARG();
+			if (vlan_parse_qos_map(&argc, &argv, n,
+					       IFLA_VLAN_INGRESS_QOS))
+				invarg("invalid ingress-qos-map", *argv);
+			continue;
+		} else if (matches(*argv, "egress-qos-map") == 0) {
+			NEXT_ARG();
+			if (vlan_parse_qos_map(&argc, &argv, n,
+					       IFLA_VLAN_EGRESS_QOS))
+				invarg("invalid egress-qos-map", *argv);
+			continue;
+		} else if (matches(*argv, "help") == 0) {
+			explain();
+			return -1;
+		} else {
+			fprintf(stderr, "vlan: what is \"%s\"?\n", *argv);
+			explain();
+			return -1;
+		}
+		argc--, argv++;
+	}
+
+	if (flags.mask)
+		addattr_l(n, 1024, IFLA_VLAN_FLAGS, &flags, sizeof(flags));
+
+	return 0;
+}
+
+static void vlan_print_map(FILE *f, char *name, struct rtattr *attr)
+{
+	struct ifla_vlan_qos_mapping *m;
+	struct rtattr *i;
+	int rem;
+
+	fprintf(f, "\n      %s { ", name);
+
+	rem = RTA_PAYLOAD(attr);
+	for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
+		m = RTA_DATA(i);
+		fprintf(f, "%u:%u ", m->from, m->to);
+	}
+	fprintf(f, "} ");
+}
+
+static void vlan_print_flags(FILE *fp, __u32 flags)
+{
+	fprintf(fp, "<");                                                                     
+#define _PF(f)	if (flags & VLAN_FLAG_##f) { \
+			flags &= ~ VLAN_FLAG_##f; \
+			fprintf(fp, #f "%s", flags ? "," : ""); \
+		}
+	_PF(REORDER_HDR);
+#undef _PF
+	if (flags)
+		fprintf(fp, "%x", flags);
+	fprintf(fp, "> ");
+}
+
+static void vlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
+{
+	struct ifla_vlan_flags *flags;
+	if (!tb)
+		return;
+
+	if (!tb[IFLA_VLAN_ID] ||
+	    RTA_PAYLOAD(tb[IFLA_VLAN_ID]) < sizeof(__u16))
+		return;
+
+	fprintf(f, "id %u ", *(__u16 *)RTA_DATA(tb[IFLA_VLAN_ID]));
+
+	if (tb[IFLA_VLAN_FLAGS]) {
+		if (RTA_PAYLOAD(tb[IFLA_VLAN_FLAGS]) < sizeof(*flags))
+			return;
+		flags = RTA_DATA(tb[IFLA_VLAN_FLAGS]);
+		vlan_print_flags(f, flags->flags);
+	}
+	if (tb[IFLA_VLAN_INGRESS_QOS])
+		vlan_print_map(f, "ingress-qos-map", tb[IFLA_VLAN_INGRESS_QOS]);
+	if (tb[IFLA_VLAN_EGRESS_QOS])
+		vlan_print_map(f, "egress-qos-map", tb[IFLA_VLAN_EGRESS_QOS]);
+}
+
+struct link_util vlan_link_util = {
+	.id		= "vlan",
+	.maxattr	= IFLA_VLAN_MAX,
+	.parse_opt	= vlan_parse_opt,
+	.print_opt	= vlan_print_opt,
+};

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [IPROUTE 00/02]: rtnl_link support
  2007-06-13 17:02 [IPROUTE 00/02]: rtnl_link support Patrick McHardy
  2007-06-13 17:02 ` [IPROUTE 01/02]: iplink: use netlink for link configuration Patrick McHardy
  2007-06-13 17:02 ` [IPROUTE 02/02]: VLAN support Patrick McHardy
@ 2007-06-13 17:48 ` Stephen Hemminger
  2007-06-13 18:11   ` Patrick McHardy
  2 siblings, 1 reply; 6+ messages in thread
From: Stephen Hemminger @ 2007-06-13 17:48 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: netdev, Patrick McHardy

On Wed, 13 Jun 2007 19:02:32 +0200 (MEST)
Patrick McHardy <kaber@trash.net> wrote:

> Hi Stephen,
> 
> these patches add support for the rtnl_link stuff and VLAN configuration
> to iproute. Since the old link configuration was entirely ioctl based and
> mixing the two would be really ugly, this patch keeps the old ioctl stuff
> guarded by an ifdef (defaults to enabled) and probes for support for
> using RTM_NEWLINK. Tested to work properly on both old and patched kernel.
> 
> I've added a new -d[etail] flag to ip, the driver specific things are only
> printed when it is specified. I did this mainly because I'm not sure how
> careful we want to be not to confuse people using sed/awk/... on iproute
> output. I would prefer to have the information always shown, but I'll
> leave that decision up to you.
> 
> Changes since the last post:
> 
> - Only call link argument parsing function if arguments are present
> - Support xstats dumping
> - Add sanitized if_vlan.h file for VLAN flag definition
> - Support setting/changing VLAN flags
> 
> Please apply, thanks.

I'm putting out a new iproute2 next week. IF this is in mainline, it will
go in then. If not, then there will be a development branch

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [IPROUTE 00/02]: rtnl_link support
  2007-06-13 17:48 ` [IPROUTE 00/02]: rtnl_link support Stephen Hemminger
@ 2007-06-13 18:11   ` Patrick McHardy
  2007-06-13 19:51     ` David Miller
  0 siblings, 1 reply; 6+ messages in thread
From: Patrick McHardy @ 2007-06-13 18:11 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev

Stephen Hemminger wrote:
> On Wed, 13 Jun 2007 19:02:32 +0200 (MEST)
> Patrick McHardy <kaber@trash.net> wrote:
> 
>>Please apply, thanks.
> 
> 
> I'm putting out a new iproute2 next week. IF this is in mainline, it will
> go in then. If not, then there will be a development branch


Thanks. The first version of these patches are already in
the net-2.6.23 tree, Dave is going to replace them with this
version. Unlikely to be in mainline until next week though :)

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [IPROUTE 00/02]: rtnl_link support
  2007-06-13 18:11   ` Patrick McHardy
@ 2007-06-13 19:51     ` David Miller
  0 siblings, 0 replies; 6+ messages in thread
From: David Miller @ 2007-06-13 19:51 UTC (permalink / raw)
  To: kaber; +Cc: shemminger, netdev

From: Patrick McHardy <kaber@trash.net>
Date: Wed, 13 Jun 2007 20:11:58 +0200

> Stephen Hemminger wrote:
> > On Wed, 13 Jun 2007 19:02:32 +0200 (MEST)
> > Patrick McHardy <kaber@trash.net> wrote:
> > 
> >>Please apply, thanks.
> > 
> > 
> > I'm putting out a new iproute2 next week. IF this is in mainline, it will
> > go in then. If not, then there will be a development branch
> 
> 
> Thanks. The first version of these patches are already in
> the net-2.6.23 tree, Dave is going to replace them with this
> version. Unlikely to be in mainline until next week though :)

Right this is 2.6.23 stuff and it is in my net-2.6.23 tree
already.

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2007-06-13 19:51 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-06-13 17:02 [IPROUTE 00/02]: rtnl_link support Patrick McHardy
2007-06-13 17:02 ` [IPROUTE 01/02]: iplink: use netlink for link configuration Patrick McHardy
2007-06-13 17:02 ` [IPROUTE 02/02]: VLAN support Patrick McHardy
2007-06-13 17:48 ` [IPROUTE 00/02]: rtnl_link support Stephen Hemminger
2007-06-13 18:11   ` Patrick McHardy
2007-06-13 19:51     ` David Miller

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).