[PATCH]: iplink: add VLAN support

Patrick McHardy kaber at trash.net
Thu Jul 25 16:32:19 UTC 2013


Since I didn't receive any, here's a non-RFC submission:

The following patch adds support for specifying device specific parameters
to "ip link add" and support for VLAN configuration. Modern features such
as GVRP, MVRP, 802.1ad and some minor features are not supported through
vconfig and won't be in the future, so this is needed to make use of these
features.

Changes to last posting:

- define IFLA_VLAN_* attributes if not defined by system headers

The IFLA_VLAN_* attributes were introduced at the same time as the
RTNL link API except the IFLA_VLAN_PROTOCOL attribute, which was added
just recently, so we can assume that if IFLA_LINKINFO is not defined,
none of the IFLA_VLAN_* attributes is defined. IFLA_VLAN_PROTOCOL always
needs to be tested for seperately since it was added later.

-------------- next part --------------
commit acd1c048a9d0a8d256a69eb963a910d4d90b0e2d
Author: Patrick McHardy <kaber at trash.net>
Date:   Wed Jul 10 12:41:28 2013 +0200

    iplink: add VLAN support
    
    Add support for configuring VLAN devices to "ip link". Modern VLAN features
    such as GVRP, MVRP, 802.1ad etc. are not supported through the vconfig command.
    
    Signed-off-by: Patrick McHardy <kaber at trash.net>

diff --git a/networking/libiproute/iplink.c b/networking/libiproute/iplink.c
index bad2017..39c6fa5 100644
--- a/networking/libiproute/iplink.c
+++ b/networking/libiproute/iplink.c
@@ -1,6 +1,7 @@
 /* vi: set sw=4 ts=4: */
 /*
  * Authors: Alexey Kuznetsov, <kuznet at ms2.inr.ac.ru>
+ * 			Patrick McHardy <kaber at trash.net>
  *
  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  */
@@ -8,6 +9,7 @@
 #include <net/if_packet.h>
 #include <netpacket/packet.h>
 #include <netinet/if_ether.h>
+#include <linux/if_vlan.h>
 
 #include "ip_common.h"  /* #include "libbb.h" is inside */
 #include "rt_names.h"
@@ -16,6 +18,12 @@
 #ifndef IFLA_LINKINFO
 # define IFLA_LINKINFO 18
 # define IFLA_INFO_KIND 1
+# define IFLA_INFO_DATA 2
+# define IFLA_VLAN_ID 1
+# define IFLA_VLAN_FLAGS 2
+#endif
+#ifndef IFLA_VLAN_PROTOCOL
+# define IFLA_VLAN_PROTOCOL 5
 #endif
 
 /* taken from linux/sockios.h */
@@ -277,6 +285,111 @@ static int ipaddr_list_link(char **argv)
 	return ipaddr_list_or_flush(argv, 0);
 }
 
+static int vlan_parse_opt(char **argv, struct nlmsghdr *n, unsigned int size)
+{
+	static const char keywords[] ALIGN1 =
+		"id\0"
+		"reorder_hdr\0"
+		"gvrp\0"
+		"mvrp\0"
+		"loose_binding\0"
+		"protocol\0";
+	static const char protocols[] ALIGN1 =
+		"802.1q\0"
+		"802.1ad\0";
+	static const char str_on_off[] ALIGN1 =
+		"on\0"
+		"off\0";
+	enum {
+		ARG_id = 0,
+		ARG_reorder_hdr,
+		ARG_gvrp,
+		ARG_mvrp,
+		ARG_loose_binding,
+		ARG_protocol,
+	};
+	enum {
+		PROTO_8021Q = 0,
+		PROTO_8021AD,
+	};
+	enum {
+		PARM_on = 0,
+		PARM_off
+	};
+	smalluint arg;
+	uint16_t id, proto;
+	struct ifla_vlan_flags flags = {};
+
+	while (*argv) {
+		arg = index_in_substrings(keywords, *argv);
+		if (arg == ARG_id) {
+			NEXT_ARG();
+			id = get_u16(*argv, "id");
+			addattr_l(n, size, IFLA_VLAN_ID, &id, sizeof(id));
+		} else if (arg == ARG_protocol) {
+			NEXT_ARG();
+			arg = index_in_substrings(protocols, *argv);
+			if (arg == PROTO_8021Q)
+				proto = ETH_P_8021Q;
+			else if (arg == PROTO_8021AD)
+				proto = ETH_P_8021AD;
+			else
+				bb_error_msg_and_die("unknown VLAN encapsulation protocol %s",
+								     *argv);
+
+			addattr_l(n, size, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto));
+		} else {
+			int param;
+			NEXT_ARG();
+			param = index_in_strings(str_on_off, *argv);
+
+			if (arg == ARG_reorder_hdr) {
+				if (param < 0)
+					die_must_be_on_off("reorder_hdr");
+
+				flags.mask |= VLAN_FLAG_REORDER_HDR;
+				if (param == PARM_on)
+					flags.flags |= VLAN_FLAG_REORDER_HDR;
+				else
+					flags.flags &= ~VLAN_FLAG_REORDER_HDR;
+			} else if (arg == ARG_gvrp) {
+				if (param < 0)
+					die_must_be_on_off("gvrp");
+
+				flags.mask |= VLAN_FLAG_GVRP;
+				if (param == PARM_on)
+					flags.flags |= VLAN_FLAG_GVRP;
+				else
+					flags.flags &= ~VLAN_FLAG_GVRP;
+			} else if (arg == ARG_mvrp) {
+				if (param < 0)
+					die_must_be_on_off("mvrp");
+
+				flags.mask |= VLAN_FLAG_MVRP;
+				if (param == PARM_on)
+					flags.flags |= VLAN_FLAG_MVRP;
+				else
+					flags.flags &= ~VLAN_FLAG_MVRP;
+			} else if (arg == ARG_loose_binding) {
+				if (param < 0)
+					die_must_be_on_off("loose_binding");
+
+				flags.mask |= VLAN_FLAG_LOOSE_BINDING;
+				if (param == PARM_on)
+					flags.flags |= VLAN_FLAG_LOOSE_BINDING;
+				else
+					flags.flags &= ~VLAN_FLAG_LOOSE_BINDING;
+			}
+		}
+		argv++;
+	}
+
+	if (flags.mask)
+		addattr_l(n, size, IFLA_VLAN_FLAGS, &flags, sizeof(flags));
+
+	return 0;
+}
+
 #ifndef NLMSG_TAIL
 #define NLMSG_TAIL(nmsg) \
 	((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
@@ -286,12 +399,17 @@ static int do_change(char **argv, const unsigned rtm)
 {
 	static const char keywords[] ALIGN1 =
 		"link\0""name\0""type\0""dev\0";
+	static const char types[] ALIGN1 =
+		"vlan\0";
 	enum {
 		ARG_link,
 		ARG_name,
 		ARG_type,
 		ARG_dev,
 	};
+	enum {
+		TYPE_vlan,
+	};
 	struct rtnl_handle rth;
 	struct {
 		struct nlmsghdr  n;
@@ -321,6 +439,8 @@ static int do_change(char **argv, const unsigned rtm)
 		} else if (arg == ARG_type) {
 			NEXT_ARG();
 			type_str = *argv;
+			argv++;
+			break;
 		} else {
 			if (arg == ARG_dev) {
 				if (dev_str)
@@ -339,6 +459,18 @@ static int do_change(char **argv, const unsigned rtm)
 		addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0);
 		addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type_str,
 				strlen(type_str));
+
+		arg = index_in_substrings(types, type_str);
+		if (*argv) {
+			struct rtattr *data = NLMSG_TAIL(&req.n);
+			addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0);
+
+			if (arg == TYPE_vlan)
+				vlan_parse_opt(argv, &req.n, sizeof(req));
+
+			data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data;
+		}
+
 		linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
 	}
 	if (rtm != RTM_NEWLINK) {


More information about the busybox mailing list