[BusyBox] vlanconfig - alternative to vconfig applet

Manuel Novoa III mjn3 at codepoet.org
Mon Jan 27 22:35:05 UTC 2003


Hello,

On Sun, Jan 26, 2003 at 05:48:35PM +0200, Nick Fedchik wrote:
> On Sat, 25 Jan 2003, Nick Fedchik wrote:
> 
> ...
> > so much more changes and have made a decision to make new
> > applet - vlanconfig.
> > The patch attached.
> Sorry, that previous patch was very buggy! I was very tired, so
> made a lot of mistakes. I hope it was'nt critical to anyone.
> Here the new patch instead of previous.
> Also this version has heavy redesigned, so I don't made a patch
> over previous patch, but post completelly new patch.

While I commend your motivation and efforts, I suspect that anyone
using vconfig (I don't btw) isn't likely to want to change their
scripts, etc. to use your different command line args.  I certainly
agree though that the current vconfig.c applet is a "bloated pig"
and I've already made several comments to Erik about it.

That being said, I thought I'd give some constructive feedback
on your applet, as well as include a vconfig applet that I did a
few size-optimization iterations on.  As a comparison,
on i386 with gcc (GCC) 3.2.2 20030109 (Debian prerelease), I get

  text    data     bss     dec     hex filename
  2835       0       0    2835     b13 vconfig-dist.o  (current vconfig)
  1089       0       0    1089     441 vlanconfig.o    (your alternate)
   798       0       0     798     31e vconfig.o       (my vconfig)

As I said, I don't use vconfig myself, so I only tested that the
arg processing was correct.

I hope you and others find the following comments and code example useful.

Manuel

-------------------------------------------------------------------
(your applet... minus headers)

> +#define VLAN_GROUP_ARRAY_LEN 4096
> +#define SIOCSIFVLAN	0x8983	/* Set 802.1Q VLAN options  */
> +
> +int vlanconfig_main(int argc, char **argv)
> +{
> +	int fd;
> +	struct vlan_ioctl_args ifr;
> +	int cmd, set_opt;
> +	char *endptr = NULL;

There's no need to initialize endptr.

> +	char *conf_file_name = "/proc/net/vlan/config";
> +	char *int_len_msg = "Interface name must be less than";

Since these never change, it would be smaller to do

static const char conf_file_name[] = ...
static const char int_len_msg[] = ...

> +
> +/*
> +Usage: add      <iface-name> <vid>
> +       del      <vlan-name>
> +       set	nametype  {1|2|3|4}
> +       set	flag	<vlan-name>
> +       set	egress  <vlan-name>	<skb_priority>   <vlan_qos> 0-7
> +       set	ingress <vlan-name>	<skb_priority>   <vlan_qos>
> +
> +*/
> +
> +	enum vlan_cmd_num { cmd_add, cmd_del, cmd_set };
> +
> +#define VLAN_CMD_HIGHEST 3
> +	char *vlan_cmd[VLAN_CMD_HIGHEST] = {
> +		"add",
> +		"del",
> +		"set"
> +	};
> +
> +	enum vlan_cmd_set_opt_num { set_nametype, set_flag, set_egress,
> +		set_ingress
> +	};
> +
> +#define VLAN_CMD_SET_OPT_HIGHEST 4
> +	char *vlan_cmd_set_opt[VLAN_CMD_SET_OPT_HIGHEST] = {
> +		"nametype",
> +		"flag",
> +		"egress",
> +		"ingress"
> +	};

Similarly, it would be smaller if these were static const as well.
Also, if you were writing library code and compiling with -fPIC, there
would be some overhead in initializing the arrays regardless.

> +
> +	if ((argc < 3) || (argc > 6))

The test

   if (((unsigned int)(argc - 3)) > 3)

is equivalent, but smaller.

> +		show_usage();
> +
> +	if ((fd = open(conf_file_name, O_RDONLY)) < 0)	// Open up the /proc/vlan/config
> +		error_msg_and_die("open %s: %m\n", conf_file_name);
> +	close(fd);

It isn't really necessary to close fd.  Hence, storing fd isn't necessary
either.

> +
> +	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)	/* We use sockets now, instead of the file descriptor */
> +		error_msg_and_die("socket: %m\n");

It may generate smaller code if the socket call/fd assignment is closer
to the ioctl call.

> +
> +	memset(&ifr, 0, sizeof(struct vlan_ioctl_args));
> +
> +	for (cmd = 0; cmd < VLAN_CMD_HIGHEST; cmd++)
> +		if (!strcasecmp(vlan_cmd[cmd], argv[1]))
> +			break;

Since we're guaranteed to go through the loop at least once, it is
sometimes smaller to use a do {} while, depending on the test, etc.
Your mileage may vary but it is worth looking at.

> +
> +	if (cmd == VLAN_CMD_HIGHEST)
> +		show_usage();
> +
> +	if (cmd == cmd_set) {
> +
> +		if (argc < 4)
> +			show_usage();
> +		for (set_opt = 0; set_opt < VLAN_CMD_SET_OPT_HIGHEST; set_opt++)
> +			if (!strcasecmp(vlan_cmd_set_opt[set_opt], argv[2]))
> +				break;

By creating a "set" arg prefixing the nametype/flag/egress/ingress args,
you've made it necessary to use a second loop.  Consider removing "set".

> +
> +		if (set_opt == VLAN_CMD_SET_OPT_HIGHEST)
> +			show_usage();
> +		if (set_opt == set_nametype) {
> +			ifr.u.name_type = strtoul(argv[3], &endptr, 10);
> +			if ((ifr.u.name_type > VLAN_NAME_TYPE_HIGHEST)
> +				|| (*endptr != '\0'))
> +				show_usage();
> +			ifr.cmd = SET_VLAN_NAME_TYPE_CMD;
> +		} else {
> +			if (strlen(argv[3]) > IF_NAMESIZE)	// For those cases argv[3] is interface (physical or vlan-aware)
> +				error_msg_and_die("%s %d\n", int_len_msg, IF_NAMESIZE);
> +			strcpy(ifr.device1, argv[3]);
> +
> +			if (set_opt == set_flag) {
> +/*
> +				if (argc < 5)
> +					show_usage();
> +				ifr.u.flag = strtoul(argv[4], &endptr, 2);
> +				if ((ifr.u.flag > 1) || (*endptr != '\0'))
> +					show_usage();

The argc test, strtoul call, range check is repeated code.  In my
version, the needed argc is stored in the command table and I only
need to check twice... once to make sure there are at least 3 args,
and then once when the command is determined.

I also use a static function that does the conversion and range check
to consolidate things.

> +*/
> +				ifr.u.flag = 1;
> +				ifr.cmd = SET_VLAN_FLAG_CMD;
> +			} else {
> +				if (argc < 6)
> +					show_usage();
> +				ifr.u.skb_priority = strtoul(argv[4], &endptr, 10);
> +				if ((ifr.u.skb_priority > 0xFFFF) || (*endptr != '\0'))
> +					show_usage();
> +				ifr.vlan_qos = strtoul(argv[5], &endptr, 8);
> +				if ((ifr.vlan_qos > 7) || (*endptr != '\0'))
> +					show_usage();
> +				if (set_opt == set_egress)
> +					ifr.cmd = SET_VLAN_EGRESS_PRIORITY_CMD;
> +				if (set_opt == set_ingress)
> +					ifr.cmd = SET_VLAN_INGRESS_PRIORITY_CMD;

I also store the ifr.cmd value in the command table.  Hence I only need
one 'ifr.cmd = <value>;' statment.

> +			}
> +		}
> +	} else {
> +		// general check here, argv[2] is ifname    
> +		if (strlen(argv[2]) > IF_NAMESIZE)
> +			error_msg_and_die("%s %d\n", int_len_msg, IF_NAMESIZE);
> +		strcpy(ifr.device1, argv[2]);
> +		if (cmd == cmd_add) {
> +			ifr.cmd = ADD_VLAN_CMD;
> +			if (argc < 4)
> +				show_usage();
> +			ifr.u.VID = strtoul(argv[3], &endptr, 10);	// argv[3] is VID (0-4096)
> +			if ((ifr.u.VID >= VLAN_GROUP_ARRAY_LEN) || (ifr.u.VID < 0)
> +				|| (*endptr != '\0'))
> +				show_usage();
> +		}
> +		if (cmd == cmd_del)
> +			ifr.cmd = DEL_VLAN_CMD;
> +	};
> +	if (ioctl(fd, SIOCSIFVLAN, &ifr) < 0)
> +		error_msg_and_die("ioctl error when %s %s: %m\n", vlan_cmd[cmd],
> +						  argv[2]);
> +
> +	return 0;
> +}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: vconfig.c
Type: text/x-csrc
Size: 3766 bytes
Desc: not available
Url : http://lists.busybox.net/pipermail/busybox/attachments/20030127/6360dc1e/attachment.c 


More information about the busybox mailing list